New Upstream Snapshot - ruby-xml-simple

Ready changes

Summary

Merged new upstream version: 1.1.9+git20210121.1.7b8bdf7 (was: 1.1.9).

Resulting package

Built on 2022-11-14T15:27 (took 9m20s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots ruby-xml-simple

Diff

diff --git a/CHANGES b/CHANGES
new file mode 100755
index 0000000..97473bc
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,86 @@
+Version 1.1.9:
+  - REXML dependency is explicit now in gemspec - Pavel Valena
+
+Version 1.1.8:
+  - Orgad Shaneh added SelfClose option.
+
+Version 1.1.7:
+  - Changed license to MIT.
+
+Version 1.1.5:
+  - Added 'AttrToSymbol' option that converts attribute
+    names to Ruby symbols - Amos Bieler
+
+Version 1.1.4:
+  - Fixed bug in has_mixed_content? reported by Dan Kubb.
+
+Version 1.1.3:
+  - Cleaned up gemspec.
+
+Version 1.0.14:
+  - XmlSimple.xml_in now supports symbols for option names (fix provided
+    by Bruce Adams).
+
+Version 1.0.13:
+  - Fixed a bug that led to problems when outputting symbols on Ruby 1.8.x
+    (reported by Chris St. John).
+
+Version 1.0.12:
+  - Works with Ruby 1.9.1, 1.8.x
+  - Accepts compressed XML documents represented by Zlib::GzipReader objects
+    (added by Jay Lawrence).
+  - Added 'AttrPrefix' option (contributed by Reid Morrison).
+
+Version 1.0.11:
+  - Ken Mitchell fixed a bug in option handling.
+
+Version 1.0.10:
+  - Nick Sieger fixed node_to_text.
+
+Version 1.0.9:
+  - Added 'KeyToSymbol' option that converts Tag names to ruby
+    symbols - Keith Veleba
+  - Fixed a bug in markup decoding and encoding. Reported by
+    Yan Zhang.
+
+Version 1.0.6:
+  - Fixed a bug (reported by Curtis Schofield) that led to
+    problems with empty elements that had only attributes.
+
+Version 1.0.5:
+  - Corrected version info in INSTALL file.
+
+Version 1.0.4:
+  - Fixed small bug in install.rb.
+
+Version 1.0.3:
+  - Works with Ruby 1.8.0 and current REXML now.
+
+Version 1.0.2:
+  - All objects can be encoded now by value_to_xml. The Perl
+    version excluded blessed references, but in Ruby each
+    object has a to_s method, so this restriction wasn't
+    necessary. Thanx to Daniel Wu for "pointing" this out.
+
+Version 1.0.1:
+  - Removed a bug (reported by Paul DuBois) that led to a
+    warning in XmlSimple.initialize.
+
+Version 1.0.0:
+  - Added three caching models.
+  - Option names are case insensitive now and underscores
+    are no longer significant, i.e.
+      force_array == ForceArray == forcearray == fOR__CEArray
+  - 'force_array' option additionally works with regexes
+    now.
+  - Added 'indent' option that allows to specify an
+    arbitrary string to be used for indentation by
+    xml_out.
+  - Added 'GroupTags' option.
+  - Added 'Variables' option.
+  - Added 'VarAttr' option.
+  - Added 'NormaliseSpace' option.
+  - Added 'NoIndent' option.
+
+Version 0.6.0:
+  - First working version.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7e6060c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2003-2021 Maik Schmidt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.adoc b/README.adoc
new file mode 100644
index 0000000..e9ac863
--- /dev/null
+++ b/README.adoc
@@ -0,0 +1,1027 @@
+:lang: en
+
+= XmlSimple - XML made easy
+
+== Introduction
+
+The _XmlSimple_ class offers an easy API to read and write XML. It is a Ruby  translation of Grant McLean's Perl module http://www.cpan.org/modules/by-module/XML/GRANTM/[XML::Simple]. Please note, that this tutorial was originally written by Grant McLean. I have only converted it to Asciidoc and adjusted it for the Ruby version.
+
+== Installation
+
+XmlSimple is available as a Gem, so you can install it as follows:
+
+....
+  gem install xml-simple
+....
+
+== Quick Start
+
+Say you have a script called _foo_ and a file of configuration options called _foo.xml_ containing this:
+
+....
+  <config logdir="/var/log/foo/" debugfile="/tmp/foo.debug">
+    <server name="sahara" osname="solaris" osversion="2.6">
+      <address>10.0.0.101</address>
+      <address>10.0.1.101</address>
+    </server>
+    <server name="gobi" osname="irix" osversion="6.5">
+      <address>10.0.0.102</address>
+    </server>
+    <server name="kalahari" osname="linux" osversion="2.0.34">
+      <address>10.0.0.103</address>
+      <address>10.0.1.103</address>
+    </server>
+  </config>
+....
+
+The following lines of code in _foo_:
+
+....
+  require 'xmlsimple'
+  config = XmlSimple.xml_in('foo.xml', { 'KeyAttr' => 'name' })
+....
+
+will 'slurp' the configuration options into the Hash _config_ (if no arguments are passed to _xml_in_ the name and location of the XML file will be inferred from name and location of the script). You can dump out the contents of the Hash using `p config`, which will produce something like this (formatting has been adjusted for brevity):
+
+....
+{
+  'logdir'        => '/var/log/foo/',
+  'debugfile'     => '/tmp/foo.debug',
+  'server'        => {
+    'sahara'        => {
+      'osversion'     => '2.6',
+      'osname'        => 'solaris',
+      'address'       => [ '10.0.0.101', '10.0.1.101' ]
+    },
+    'gobi'          => {
+      'osversion'     => '6.5',
+      'osname'        => 'irix',
+      'address'       => [ '10.0.0.102' ]
+    },
+    'kalahari'      => {
+      'osversion'     => '2.0.34',
+      'osname'        => 'linux',
+      'address'       => [ '10.0.0.103', '10.0.1.103' ]
+    }
+  }
+}
+....
+
+Your script could then access the name of the log directory like this:
+
+....
+  puts config['logdir']
+....
+
+Similarly, the second address on the server 'kalahari' could be referenced as:
+
+....
+  puts config['server']['kalahari']['address'][1]
+....
+
+What could be simpler? (Rhetorical).
+
+For simple requirements, that's really all there is to it. If you want to store your XML in a different directory or file, or pass it in as a string, you'll need to check out the section on <<options, options>>. If you want to turn off or tweak the array folding feature (that neat little transformation that produced _config['server'])_ you'll find options for that as well.
+
+If you want to generate XML (for example to write a modified version of _config_ back out as XML), check out _xml_out_.
+
+== Description
+
+The _XmlSimple_ class provides a simple API layer on top of the https://github.com/ruby/rexml/[REXML] parser. Additionally, two functions are exported: _xml_in_ and _xml_out_.
+
+The simplest approach is to call these two functions directly, but an optional object-oriented interface (see the section on <<OOInterface, Optional OO Interface>> below) allows them to be called as methods of an _XmlSimple_ object.
+
+=== xml_in
+
+Parses XML formatted data and returns a reference to a data structure which contains the same information in a more readily accessible form. (Skip down to the section on <<examples, examples>> below, for more sample code).
+
+_xml_in_ accepts an optional XML specifier followed by a Hash containing 'name => value' option pairs. The XML specifier can be a filename, nil, or an IO object.
+
+==== A Filename
+
+If the filename contains no directory components _xml_in_ will look for the file in each directory in the searchpath (see the section on <<options, options>> below). For example:
+
+....
+    ref = XmlSimple.xml_in('/etc/params.xml')
+....
+
+==== nil
+
+If there is no XML specifier, _xml_in_ will check the script directory and each of the searchpath directories for a file with the same name as the script but with the extension '.xml'. Note: if you wish to specify options, you must specify the value _nil_:
+
+....
+    ref = XmlSimple.xml_in(nil, { 'ForceArray' => false })
+....
+
+==== A String of XML
+
+A string containing XML (recognised by the presence of '<' and '>' characters) will be parsed directly. For example:
+
+....
+    ref = XmlSimple.xml_in('<opt username="bob" password="flurp" />')
+....
+
+==== An IO object
+
+An IO object will be read to EOF and its contents parsed. For example:
+
+....
+    file = File.open('/etc/params.xml')
+    ref  = XmlSimple.xml_in(file)
+....
+
+=== xml_out
+
+Takes a data structure (generally a Hash) and returns an XML encoding of that structure. If the resulting XML is parsed using _xml_in_, it will return a data structure equivalent to the original.
+
+When translating hashes to XML, hash keys which have a leading '-' will be silently skipped. This is the approved method for marking elements of a data structure which should be ignored by _xml_out_. (Note: If these items were not skipped the key names would be emitted as element or attribute names with a leading '-' which would not be valid XML).
+
+=== Caveats
+
+Some care is required in creating data structures which will be passed to _xml_out_. Hash keys from the data structure will be encoded as either XML element names or attribute names. Therefore, you should use hash key names which conform to the relatively strict XML naming rules:
+
+Names in XML must begin with a letter. The remaining characters may be letters, digits, hyphens (-), underscores (_) or full stops (.). It is also allowable to include one colon (:) in an element name but this should only be used when working with namespaces - a facility well beyond the scope of _XmlSimple_.
+
+You can use other punctuation characters in hash values (just not in hash keys) however _XmlSimple_ does not support dumping binary data.
+
+If you break these rules, the current implementation of _xml_out_ will simply emit non-compliant XML which will be rejected if you try to read it back in. (A later version of _XmlSimple_ might take a more proactive approach).
+
+Note also that although you can nest hashes and arrays to arbitrary levels, recursive data structures are not supported and will cause _xml_out_ to raise an exception.
+
+[[options]]
+== Options
+
+_IMPORTANT NOTE FOR USERS OF THE PERL VERSION!_ The default values of some options have changed, some options are not supported and I have added new options, too:
+
+* 'ForceArray' is _true_ by default.
+* 'KeyAttr' defaults to _[]_ and not to _['name', 'key', 'id']_.
+* The SAX parts of XML::Simple are currently not supported.
+* Namespaces are currently not supported.
+* Currently, there is no 'strict mode'.
+* 'AnonymousTag' is not available in the current Perl version.
+* 'Indent' is not available in the current Perl version.
+* The Perl version does not support so called blessed references and raises an exception ("can't encode value of type"), if one is used. The Ruby version supports all object types, because every object in Ruby has a _to_s_ method.
+
+_XmlSimple_ supports a number of options. If you find yourself repeatedly having to specify the same options, you might like to investigate the section on link:#OOInterface["Optional OO Interface"] below.
+
+Because there are so many options, it's hard for new users to know which ones are important, so here are the two you really need to know about:
+
+* Check out 'ForceArray' because you'll almost certainly want to leave it on.
+* Make sure you know what the 'KeyAttr' option does and what its default value is because it may surprise you otherwise.
+
+Both _xml_in_ and _xml_out_ expect a single argument followed by a Hash containing options. So, an option takes the form of a 'name => value' pair. The options listed below are marked with 'in' if they are recognised by _xml_in_ and 'out' if they are recognised by _xml_out_.
+
+Each option is also flagged to indicate whether it is:
+
+* 'important' - don't use the module until you understand this
+* 'handy' - you can skip this on the first time through
+* 'advanced' - you can skip this on the second time through
+* 'seldom used' - you'll probably never use this unless you were the person that requested the feature
+
+The options are listed alphabetically.
+
+_Note_: Option names are not case-sensitive, so you can use the mixed case versions shown here. Additionally, you can put underscores between the words (for example 'key_attr').
+
+=== AnonymousTag => 'tag name' (in + out) (seldom used)
+
+By default, the tag to declare an anonymous value is 'anon'. Using option 'AnonymousTag' you can set it to an arbitrary string (that must obey to the XML naming rules, of course).
+
+=== Cache => [ cache scheme(s) ] (in) (advanced)
+
+Because loading the REXML parser module and parsing an XML file can consume a significant number of CPU cycles, it is often desirable to cache the output of _xml_in_ for later reuse.
+
+When parsing from a named file, _XmlSimple_ supports a number of caching schemes. The 'Cache' option may be used to specify one or more schemes (using an anonymous array). Each scheme will be tried in turn in the hope of finding a cached pre-parsed representation of the XML file. If no cached copy is found, the file will be parsed and the first cache scheme in the list will be used to save a copy of the results. The following cache schemes have been implemented:
+
+==== storable
+
+Utilises Marshal to read/write a cache file with the same name as the XML file but with the extension _.stor_.
+
+==== mem_share
+
+When a file is first parsed, a copy of the resulting data structure is retained in memory in _XmlSimple_'s namespace. Subsequent calls to parse the same file will return a reference to this structure. This cached version will persist only for the life of the Ruby interpreter (which in the case of mod_ruby for example, may be some significant time).
+
+Because each caller receives a reference to the same data structure, a change made by one caller will be visible to all. For this reason, the reference returned should be treated as read-only.
+
+==== mem_copy
+
+This scheme works identically to 'mem_share' (above) except that each caller receives a reference to a new data structure which is a copy of the cached version. Copying the data structure will add a little processing overhead, therefore this scheme should only be used where the caller intends to modify the data structure (or wishes to protect itself from others who might). This scheme uses the Marshal module to perform the copy.
+
+_Warning!_ The memory-based caching schemes compare the timestamp on the file to the time when it was last parsed. If the file is stored on an NFS filesystem (or other network share) and the clock on the file server is not exactly synchronised with the clock where your script is run, updates to the source XML file may appear to be ignored.
+
+=== ContentKey => 'keyname' (in + out) (seldom used)
+
+When text content is parsed to a hash value, this option let's you specify a name for the hash key to override the default 'content'. So for example:
+
+....
+    XmlSimple.xml_in('<opt one="1">Text</opt>', { 'ContentKey' => 'text' })
+....
+
+will parse to:
+
+....
+    { 'one' => '1', 'text' => 'Text' }
+....
+
+instead of:
+
+....
+    { 'one' => '1', 'content' => 'Text' }
+....
+
+_xml_out_ will also honour the value of this option when converting a hash to XML.
+
+You can also prefix your selected key name with a '-' character to have _xml_in_ try a little harder to eliminate unnecessary 'content' keys after array folding. For example:
+
+....
+  XmlSimple.xml_in(%q(
+    <opt>
+      <item name="one">First<item>
+      <item name="two">Second<item>
+    <opt>), {
+  'KeyAttr'    => { 'item' => 'name' },
+  'ForceArray' => [ 'item' ],
+  'ContentKey' => '-content'
+})
+....
+
+will parse to:
+
+....
+{
+  'item' => {
+    'one'  =>  'First',
+    'two'  =>  'Second'
+  }
+}
+....
+
+rather than this (without the '-'):
+
+....
+{
+  'item' => {
+    'one'  => { 'content' => 'First' },
+    'two'  => { 'content' => 'Second' }
+  }
+}
+....
+
+=== ForceArray => true | false (in) (IMPORTANT!)
+
+This option should be set to _true_ to force nested elements to be represented as arrays even when there is only one. For example, with 'ForceArray' enabled, this XML:
+
+....
+<opt>
+  <name>value</name>
+</opt>
+....
+
+would parse to this:
+
+....
+{
+  'name' => [ 'value' ]
+}
+....
+
+instead of this (the default):
+
+....
+{
+  'name' => 'value'
+}
+....
+
+This option is especially useful if the data structure is likely to be written back out as XML and the default behaviour of rolling single nested elements up into attributes is not desirable.
+
+If you are using the array folding feature, you should almost certainly enable this option. If you do not, single nested elements will not be parsed to arrays and therefore will not be candidates for folding to a hash.
+
+The option is _true_ by default.
+
+=== ForceArray => [ name(s) ] (in) (IMPORTANT!)
+
+This alternative form of the 'ForceArray' option allows you to specify a list of element names which should always be forced into an array representation, rather than the 'all or nothing' approach above.
+
+It is also possible to include compiled regular expressions in the list - any element names which match the pattern will be forced to arrays. If the list contains only a single regex, then it is not necessary to enclose it in an Array. For example,
+
+....
+'ForceArray' => %r(_list$)
+....
+
+=== ForceContent (in) (seldom used)
+
+When _xml_in_ parses elements which have text content as well as attributes, the text content must be represented as a hash value rather than a simple scalar. This option allows you to force text content to always parse to a hash value even when there are no attributes. So, for example:
+
+....
+  xml =%q(
+    <opt>
+      <x>text1</x>
+      <y a="2">text2</y>
+    </opt>)
+  XmlSimple.xml_in(xml, { 'ForceContent' => true })
+....
+
+will parse to:
+
+....
+    {
+      'x' => {             'content' => 'text1' },
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+....
+
+instead of:
+
+....
+    {
+      'x' => 'text1',
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+....
+
+=== GroupTags => { grouping tag => grouped tag } (in + out) (handy)
+
+You can use this option to eliminate extra levels of indirection in your Ruby data structure. For example this XML:
+
+....
+  xml = %q(
+  <opt>
+    <searchpath>
+      <dir>usr/bin<dir>
+      <dir>usr/local/bin<dir>
+      <dir>usr/X11/bin<dir>
+    <searchpath>
+  <opt>)
+....
+
+Would normally be read into a structure like this:
+
+....
+ {
+   'searchpath' => {
+     'dir' => [ '/usr/bin', '/usr/local/bin', '/usr/X11/bin' ]
+   }
+ }
+....
+
+But when read in with the appropriate value for 'GroupTags':
+
+....
+    opt = XmlSimple.xml_in(xml, { 'GroupTags' => { 'searchpath' => 'dir' })
+....
+
+It will return this simpler structure:
+
+....
+    {
+      'searchpath' => [ '/usr/bin', '/usr/local/bin', '/usr/X11/bin' ]
+    }
+....
+
+You can specify multiple 'grouping element' to 'grouped element' mappings in the same Hash. If this option is combined with 'KeyAttr', the array folding will occur first and then the grouped element names will be eliminated.
+
+_xml_out_ will also use the grouptag mappings to re-introduce the tags around the grouped elements. Beware though that this will occur in all places that the 'grouping tag' name occurs - you probably don't want to use the same name for elements as well as attributes.
+
+=== Indent => 'string' (out) (seldom used)
+
+By default, _xml_out_'s pretty printing mode indents the output document using two blanks. 'Indent' allows you to use an arbitrary string for indentation.
+
+If the 'NoIndent' option is set, 'Indent' will be ignored.
+
+=== KeepRoot => true | false (in + out) (handy)
+
+In its attempt to return a data structure free of superfluous detail and unnecessary levels of indirection, _xml_in_ normally discards the root element name. Setting the 'KeepRoot' option to _true_ will cause the root element name to be retained. So after executing this code:
+
+....
+    config = XmlSimple.xml_in('<config tempdir="/tmp" />', { 'KeepRoot' => true })
+....
+
+you'll be able to reference the tempdir as _config['config']['tempdir']_ instead of the default _config['tempdir']_.
+
+Similarly, setting the 'KeepRoot' option to _true_ will tell _xml_out_ that the data structure already contains a root element name and it is not necessary to add another.
+
+=== KeyAttr => [ list ] (in + out) (IMPORTANT!)
+
+This option controls the 'array folding' feature which translates nested elements from an array to a hash. For example, this XML:
+
+....
+        <opt>
+          <user login="grep" fullname="Gary R Epstein" />
+          <user login="stty" fullname="Simon T Tyson" />
+        </opt>
+....
+
+would, by default, parse to this:
+
+....
+{
+  'user' => [
+     {
+       'login'    => 'grep',
+       'fullname' => 'Gary R Epstein'
+     },
+     {
+       'login'    => 'stty',
+       'fullname' => 'Simon T Tyson'
+     }
+   ]
+}
+....
+
+If the option 'KeyAttr => "login"' were used to specify that the 'login' attribute is a key, the same XML would parse to:
+
+....
+{
+  'user' => {
+    'stty' => {
+      'fullname' => 'Simon T Tyson'
+    },
+    'grep' => {
+      'fullname' => 'Gary R Epstein'
+    }
+  }
+}
+....
+
+The key attribute names should be supplied in an array if there is more than one. _xml_in_ will attempt to match attribute names in the order supplied. _xml_out_ will use the first attribute name supplied when 'unfolding' a hash into an array.
+
+_Note:_ the 'KeyAttr' option controls the folding of arrays. By default, a single nested element will be rolled up into a scalar rather than an array and therefore will not be folded. Use the 'ForceArray' option to force nested elements to be parsed into arrays and therefore candidates for folding into hashes.
+
+The default value for 'KeyAttr' is _[]_, that is, the array folding feature is disabled.
+
+=== KeyAttr => { list } (in + out) (IMPORTANT!)
+
+This alternative method of specifying the key attributes allows more fine grained control over which elements are folded and on which attributes. For example the option 'KeyAttr => { 'package' => 'id' } will cause any package elements to be folded on the 'id' attribute. No other elements which have an 'id' attribute will be folded at all.
+
+_Note:_ _xml_in_ will generate a warning if this syntax is used and an element which does not have the specified key attribute is encountered (for example: a 'package' element without an 'id' attribute, to use the example above).
+
+Two further variations are made possible by prefixing a '+' or a '-' character to the attribute name:
+
+The option
+
+....
+  'KeyAttr' => { 'user' => "+login" }'
+....
+
+will cause this XML:
+
+....
+<opt>
+  <user login="grep" fullname="Gary R Epstein" />
+  <user login="stty" fullname="Simon T Tyson" />
+</opt>
+....
+
+to parse to this data structure:
+
+....
+{
+  'user' => {
+    'stty' => {
+      'fullname' => 'Simon T Tyson',
+      'login'    => 'stty'
+    },
+    'grep' => {
+      'fullname' => 'Gary R Epstein',
+      'login'    => 'grep'
+    }
+  }
+}
+....
+
+The '+' indicates that the value of the key attribute should be copied rather than moved to the folded hash key.
+
+A '-' prefix would produce this result:
+
+....
+{
+  'user' => {
+    'stty' => {
+      'fullname' => 'Simon T Tyson',
+      '-login'   => 'stty'
+    },
+    'grep' => {
+      'fullname' => 'Gary R Epstein',
+      '-login'   => 'grep'
+    }
+  }
+}
+....
+
+As described earlier, _xml_out_ will ignore hash keys starting with a '-'.
+
+=== AttrPrefix => true | false (in + out) (handy)
+
+XmlSimple treats attributes and elements equally and there is no way to determine, if a certain hash key has been derived from an element name or from an attribute name. Sometimes you need this information and that's when you use the _AttrPrefix_ option:
+
+....
+xml_str = <<XML_STR
+<Customer id="12253">
+  <first_name>Joe</first_name>
+  <last_name>Joe</last_name>
+  <Address type="home">
+    <line1>211 Over There</line1>
+    <city>Jacksonville</city>
+    <state>FL</state>
+    <zip_code>11234</zip_code>
+  </Address>
+  <Address type="postal">
+    <line1>3535 Head Office</line1>
+    <city>Jacksonville</city>
+    <state>FL</state>
+    <zip_code>11234</zip_code>
+  </Address>
+</Customer>
+XML_STR
+
+result = XmlSimple.xml_in xml_str, { 'ForceArray' => false, 'AttrPrefix' => true }
+p result
+....
+
+produces:
+
+....
+{
+  "@id" => "12253",
+  "first_name" => "Joe",
+  "Address" => [
+    {
+      "city" => "Jacksonville",
+      "line1" => "211 Over There",
+      "zip_code" => "11234",
+      "@type" => "home",
+      "state" => "FL"
+    },
+    {
+      "city" => "Jacksonville",
+      "line1" => "3535 Head Office",
+      "zip_code" => "11234",
+      "@type" => "postal",
+      "state" => "FL"
+    }
+  ],
+  "last_name" => "Joe"
+}
+....
+
+As you can see all hash keys that have been derived from attributes are prefixed by an @ character, so now you know if they have been elements or attributes before. Of course, _xml_out_ knows how to correctly transform hash keys prefixed by an @ character, too:
+
+....
+    doc = REXML::Document.new XmlSimple.xml_out(result, 'AttrPrefix' => true)
+    d = ''
+    doc.write(d)
+    puts d
+....
+
+produces:
+
+....
+<opt id="12253">
+  <first_name>Joe</first_name>
+  <last_name>Joe</last_name>
+  <Address type="home">
+    <line1>211 Over There</line1>
+    <city>Jacksonville</city>
+    <state>FL</state>
+    <zip_code>11234</zip_code>
+  </Address>
+  <Address type="postal">
+    <line1>3535 Head Office</line1>
+    <city>Jacksonville</city>
+    <state>FL</state>
+    <zip_code>11234</zip_code>
+  </Address>
+</opt>
+....
+
+=== NoAttr => true | false (in + out) (handy)
+
+When used with _xml_out_, the generated XML will contain no attributes. All hash key/values will be represented as nested elements instead.
+
+When used with _xml_in_, any attributes in the XML will be ignored.
+
+=== NormaliseSpace => 0 | 1 | 2 (in) (handy)
+
+This option controls how whitespace in text content is handled. Recognised values for the option are:
+
+* 0 - The default behaviour is for whitespace to be passed through unaltered (except of course for the normalisation of whitespace in attribute values which is mandated by the XML recommendation).
+* 1 - Whitespace is normalised in any value used as a hash key (normalising means removing leading and trailing whitespace and collapsing sequences of whitespace characters to a single space).
+* 2 - Whitespace is normalised in all text content.
+
+Note: you can spell this option with a 'z' if that is more natural for you.
+
+=== NoEscape => true | false (out) (seldom used)
+
+By default, _xml_out_ will translate the characters <, >, &, ', and " to '&lt;', '&gt;', '&amp', '&apos', and '&quot' respectively. Use this option to suppress escaping (presumably because you've already escaped the data in some more sophisticated manner).
+
+=== NoIndent => true | false (out) (seldom used)
+
+Set this option to _true_ to disable _xml_out_'s default 'pretty printing' mode. With this option enabled, the XML output will all be on one line (unless there are newlines in the data) - this may be easier for downstream processing.
+
+=== KeyToSymbol => true | false (in) (handy)
+
+If set to _true_ (default is _false_) all keys are turned into symbols, that is, the following snippet
+
+....
+  doc = <<-DOC
+  <atts>
+    <x>Hello</x>
+    <y>world</y>
+    <z>
+      <inner>Inner</inner>
+    </z>
+  </atts>
+  DOC
+  p XmlSimple.xml_in(doc, 'KeyToSymbol' => true)
+....
+
+produces:
+
+....
+  {
+    :x => ["Hello"],
+    :y => ["World"],
+    :z => [ { :inner => ["Inner"] } ]
+  }
+....
+
+=== AttrToSymbol => true | false (in) (handy)
+
+If set to _true_ (default is _false_) all keys are turned into symbols, that is, the following snippet
+
+....
+  doc = <<-DOC
+  <atts>
+    <msg text="Hello, world!" />
+  </atts>
+  DOC
+  p XmlSimple.xml_in(doc, 'AttrToSymbol' => true)
+....
+
+produces:
+
+....
+  {
+    "msg" => [ { :text => "Hello, world!" } ]
+  }
+....
+
+=== OutputFile => <file specifier> (out) (handy)
+
+The default behavior of _xml_out_ is to return the XML as a string. If you wish to write the XML to a file, simply supply the filename using the 'OutputFile' option. Alternatively, you can supply an object derived from IO instead of a filename.
+
+=== RootName => 'string' (out) (handy)
+
+By default, when _xml_out_ generates XML, the root element will be named 'opt'. This option allows you to specify an alternative name.
+
+Specifying either _nil_ or the empty string for the 'RootName' option will produce XML with no root elements. In most cases the resulting XML fragment will not be 'well formed' and therefore could not be read back in by _xml_in_. Nevertheless, the option has been found to be useful in certain circumstances.
+
+=== SearchPath => [ list ] (in) (handy)
+
+Where the XML is being read from a file, and no path to the file is specified, this attribute allows you to specify which directories should be searched.
+
+If the first parameter to _xml_in_ is undefined, the default searchpath will contain only the directory in which the script itself is located. Otherwise the default searchpath will be empty.
+
+_Note:_ the current directory ('.') is not searched unless it is the directory containing the script.
+
+=== SelfClose => true | false (out)
+
+If set, _xml_out_ will use self-closing tags for empty elements. For example:
+
+....
+<element />
+....
+
+instead of
+
+....
+<element></element>
+....
+
+=== SuppressEmpty => true | '' | nil (in + out) (handy)
+
+This option controls what _xml_in_ should do with empty elements (no attributes and no content). The default behaviour is to represent them as empty hashes. Setting this option to _true_ will cause empty elements to be skipped altogether. Setting the option to _nil_ or the empty string will cause empty elements to be represented as _nil_ or the empty string respectively. The latter two alternatives are a little easier to test for in your code than a hash with no keys.
+
+=== Variables => { name => value } (in) (handy)
+
+This option allows variables in the XML to be expanded when the file is read. (there is no facility for putting the variable names back if you regenerate XML using _xml_out_).
+
+A 'variable' is any text of the form "${name}" which occurs in an attribute value or in the text content of an element. If 'name' matches a key in the supplied Hash, "${name}" will be replaced with the corresponding value from the Hash. If no matching key is found, the variable will not be replaced.
+
+=== VarAttr => 'attr_name' (in) (handy)
+
+In addition to the variables defined using 'Variables', this option allows variables to be defined in the XML. A variable definition consists of an element with an attribute called 'attr_name' (the value of the 'VarAttr' option). The value of the attribute will be used as the variable name and the text content of the element will be used as the value. A variable defined in this way will override a variable defined using the 'Variables' option. For example:
+
+....
+    XmlSimple.xml_in(%q(<opt>
+        <dir name="prefix">usr/local/apache</dir>
+        <dir name="exec_prefix">${prefix}</dir>
+        <dir name="bindir">${exec_prefix}/bin</dir>
+        </opt>), {
+     'VarAttr' => 'name', 'ContentKey' => '-content'
+     })
+....
+
+produces the following data structure:
+
+....
+{
+  'dir' => {
+           'prefix'      => '/usr/local/apache',
+           'exec_prefix' => '/usr/local/apache',
+           'bindir'      => '/usr/local/apache/bin',
+      }
+}
+....
+
+=== XmlDeclaration => _true_ | 'string' (out) (handy)
+
+If you want the output from _xml_out_ to start with the optional XML declaration, simply set the option to _true_. The default XML declaration is:
+
+....
+    <?xml version='1.0' standalone='yes'?>
+....
+
+If you want some other string (for example to declare an encoding value), set the value of this option to the complete string you require.
+
+=== conversions => { regex => lambda } (in) (handy)
+
+When importing XML documents it's often necessary to filter or transform certain elements or attributes. The _conversions_ option helps you to do this. It expects a Hash object where the keys are regular expressions identifying element or attribute names. The values are lambda functions that will be applied to the matching elements.
+
+Let's say we have a file named status.xml containing the following document:
+
+....
+<result>
+  <status>OK</status>
+  <total>10</total>
+  <failed>2</failed>
+</result>
+....
+
+The following statement
+
+....
+  conversions = {
+    /^total|failed$/ => lambda { |v| v.to_i },
+    /^status$/       => lambda { |v| v.downcase }
+  }
+
+  p XmlSimple.xml_in(
+    'status.xml',
+    :conversions => conversions,
+    :forcearray  => false
+  )
+....
+
+produces the following output:
+
+....
+{
+  'status' => 'ok',
+  'total'  => 10,
+  'failed' => 2
+}
+....
+
+[[OOInterface]]
+== Optional OO Interface
+
+The procedural interface is both simple and convenient, but if you have to define a set of default values which should be used on all subsequent calls to _xml_in_ or _xml_out_, you might prefer to use the object-oriented (OO) interface.
+
+The default values for the options described above are unlikely to suit everyone. The OO interface allows you to effectively override _XmlSimple_'s defaults with your preferred values. It works like this:
+
+First create an _XmlSimple_ parser object with your preferred defaults:
+
+....
+    xs = XmlSimple.new({ 'ForceArray' => false, 'KeepRoot' => true)
+....
+
+then call _xml_in_ or _xml_out_ as a method of that object:
+
+....
+    ref = xs.xml_in(xml)
+    xml = xs.xml_out(ref)
+....
+
+You can also specify options when you make the method calls and these values will be merged with the values specified when the object was created. Values specified in a method call take precedence.
+
+== Error Handling
+
+The XML standard is very clear on the issue of non-compliant documents. An error in parsing any single element (for example a missing end tag) must cause the whole document to be rejected. _XmlSimple_ will raise an appropriate exception if it encounters a parsing error.
+
+[[examples]]
+== Examples
+
+When _xml_in_ reads the following very simple piece of XML:
+
+....
+    <opt username="testuser" password="frodo"></opt>
+....
+
+it returns the following data structure:
+
+....
+    {
+      'username' => 'testuser',
+      'password' => 'frodo'
+    }
+....
+
+The identical result could have been produced with this alternative XML:
+
+....
+    <opt username="testuser" password="frodo" />
+....
+
+Or this (although see 'ForceArray' option for variations):
+
+....
+    <opt>
+      <username>testuser</username>
+      <password>frodo</password>
+    </opt>
+....
+
+Repeated nested elements are represented as anonymous arrays:
+
+....
+    <opt>
+      <person firstname="Joe" lastname="Smith">
+        <email>joe@smith.com</email>
+        <email>jsmith@yahoo.com</email>
+      </person>
+      <person firstname="Bob" lastname="Smith">
+        <email>bob@smith.com</email>
+      </person>
+    </opt>
+
+    {
+      'person' => [
+        {
+          'email' => [
+            'joe@smith.com',
+            'jsmith@yahoo.com'
+          ],
+          'firstname' => 'Joe',
+          'lastname' => 'Smith'
+        },
+        {
+          'email' => ['bob@smith.com'],
+          'firstname' => 'Bob',
+          'lastname' => 'Smith'
+        }
+      ]
+    }
+....
+
+Nested elements with a recognised key attribute are transformed (folded) from an array into a hash keyed on the value of that attribute, that is, calling _xml_in_ with the 'KeyAttr' set to _[key]_ will transform
+
+....
+    <opt>
+      <person key="jsmith" firstname="Joe" lastname="Smith" />
+      <person key="tsmith" firstname="Tom" lastname="Smith" />
+      <person key="jbloggs" firstname="Joe" lastname="Bloggs" />
+    </opt>
+....
+
+into
+
+....
+    {
+      'person' => {
+        'jbloggs' => {
+          'firstname' => 'Joe',
+          'lastname' => 'Bloggs'
+        },
+        'tsmith' => {
+          'firstname' => 'Tom',
+          'lastname' => 'Smith'
+        },
+        'jsmith' => {
+          'firstname' => 'Joe',
+          'lastname' => 'Smith'
+        }
+      }
+    }
+....
+
+The <anon> tag can be used to form anonymous arrays:
+
+....
+    <opt>
+      <head><anon>Col 1</anon><anon>Col 2</anon><anon>Col 3</anon></head>
+      <data><anon>R1C1</anon><anon>R1C2</anon><anon>R1C3</anon></data>
+      <data><anon>R2C1</anon><anon>R2C2</anon><anon>R2C3</anon></data>
+      <data><anon>R3C1</anon><anon>R3C2</anon><anon>R3C3</anon></data>
+    </opt>
+
+    {
+      'head' => [
+        [ 'Col 1', 'Col 2', 'Col 3' ]
+      ],
+      'data' => [
+        [ 'R1C1', 'R1C2', 'R1C3' ],
+        [ 'R2C1', 'R2C2', 'R2C3' ],
+        [ 'R3C1', 'R3C2', 'R3C3' ]
+      ]
+    }
+....
+
+Anonymous arrays can be nested to arbitrary levels and as a special case, if the surrounding tags for an XML document contain only an anonymous array the array will be returned directly rather than the usual hash:
+
+....
+    <opt>
+      <anon><anon>Col 1</anon><anon>Col 2</anon></anon>
+      <anon><anon>R1C1</anon><anon>R1C2</anon></anon>
+      <anon><anon>R2C1</anon><anon>R2C2</anon></anon>
+    </opt>
+
+    [
+      [ 'Col 1', 'Col 2' ],
+      [ 'R1C1', 'R1C2' ],
+      [ 'R2C1', 'R2C2' ]
+    ]
+....
+
+Elements which only contain text content will simply be represented as a scalar. Where an element has both attributes and text content, the element will be represented as a hash with the text content in the 'content' key:
+
+....
+    <opt>
+      <one>first</one>
+      <two attr="value">second</two>
+    </opt>
+
+    {
+      'one' => 'first',
+      'two' => { 'attr' => 'value', 'content' => 'second' }
+    }
+....
+
+Mixed content (elements which contain both text content and nested elements) will be not be represented in a useful way - element order and significant whitespace will be lost. If you need to work with mixed content, then _XmlSimple_ is not the right tool for your job - check out the next section.
+
+[[further]]
+== Where to from here?
+
+_XmlSimple_ is by nature very simple.
+
+* The parsing process liberally disposes of 'surplus' whitespace - some applications will be sensitive to this.
+* Slurping data into a hash will implicitly discard information about attribute order. Normally this would not be a problem because any items for which order is important would typically be encoded as elements rather than attributes. However, _XmlSimple_'s aggressive slurping and folding algorithms can defeat even these techniques.
+* The API offers little control over the output of _xml_out_. In particular, it is not especially likely that feeding the output from _xml_in_ into _xml_out_ will reproduce the original XML (although passing the output from _xml_out_ into _xml_in_ should reproduce the original data structure).
+* _xml_out_ cannot produce well-formed HTML unless you feed it with care - hash keys must conform to XML element naming rules and _nil_ values should be avoided.
+* _xml_out_ does not currently support encodings (although it shouldn't stand in your way if you feed it encoded data).
+* If you're attempting to get the output from _xml_out_ to conform to a specific DTD, you're almost certainly using the wrong tool for the job.
+
+If any of these points are a problem for you, then _XmlSimple_ is probably not the right class for your application.
+
+== FAQ
+
+Question: if I include XmlSimple in a rails app and run for example 'rake' in the root of the app, I always get the following warnings:
+
+....
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:275:
+  warning: already initialized constant KNOWN_OPTIONS
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:280:
+  warning: already initialized constant DEF_KEY_ATTRIBUTES
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:281:
+  warning: already initialized constant DEF_ROOT_NAME
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:282:
+  warning: already initialized constant DEF_CONTENT_KEY
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:283:
+  warning: already initialized constant DEF_XML_DECLARATION
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:284:
+  warning: already initialized constant DEF_ANONYMOUS_TAG
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:285:
+  warning: already initialized constant DEF_FORCE_ARRAY
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:286:
+  warning: already initialized constant DEF_INDENTATION
+
+  /usr/local/lib/ruby/gems/1.8/gems/xml-simple-1.0.10/lib/xmlsimple.rb:287:
+  warning: already initialized constant DEF_KEY_TO_SYMBOL
+....
+
+Answer: The reason for this is, that you're using XmlSimple explicitly in a rails app. XmlSimple is part of rails (you can find it in ./actionpack-1.12.5/lib/action_controller/vendor/xml_simple.rb). Unfortunately, the library is named "xml_simple.rb" and not "xmlsimple.rb". Ruby's "require" prevents you from loading a library two times and it does so by checking if a file name occurs more than once. In your case somewhere in the rails framework "require 'xml_simple'" is performed and you run "require 'xmlsimple'" afterwards. Hence, the library is loaded twice and all constants are redefined.
+
+A solution is to only require xml-simple unless XmlSimple has not been defined already.
+
+== Acknowledgements
+
+A big "Thank you!" goes to
+
+* Grant McLean for Perl's
+http://www.cpan.org/modules/by-module/XML/GRANTM/[XML::Simple]
+* Yukihiro Matsumoto for Ruby.
+* Sean Russell for REXML.
+* Dave Thomas for Rdoc.
+* Nathaniel Talbott for Test::Unit.
+* Minero Aoki for his setup package.
+
+== Contact
+
+If you have any suggestions or want to report bugs, please mailto:contact@maik-schmidt.de[contact] me.
diff --git a/debian/changelog b/debian/changelog
index 39b9c35..03825f2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ruby-xml-simple (1.1.9+git20210121.1.7b8bdf7-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 14 Nov 2022 15:22:22 -0000
+
 ruby-xml-simple (1.1.9-1) unstable; urgency=medium
 
   * Team upload.
diff --git a/docs/api/XmlSimple.html b/docs/api/XmlSimple.html
new file mode 100644
index 0000000..3e20807
--- /dev/null
+++ b/docs/api/XmlSimple.html
@@ -0,0 +1,2234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+
+	<title>Class: XmlSimple</title>
+
+	<link rel="stylesheet" href="./rdoc.css" type="text/css" media="screen" />
+
+	<script src="./js/jquery.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="./js/thickbox-compressed.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="./js/quicksearch.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="./js/darkfish.js" type="text/javascript"
+		charset="utf-8"></script>
+
+</head>
+<body class="class">
+
+	<div id="metadata">
+		<div id="home-metadata">
+			<div id="home-section" class="section">
+        <h3 class="section-header">
+          <a href="./index.html">Home</a>
+          <a href="./index.html#classes">Classes</a>
+          <a href="./index.html#methods">Methods</a>
+        </h3>
+			</div>
+		</div>
+
+		<div id="file-metadata">
+			<div id="file-list-section" class="section">
+				<h3 class="section-header">In Files</h3>
+				<div class="section-body">
+					<ul>
+					
+						<li><a href="./lib/xmlsimple_rb.html?TB_iframe=true&amp;height=550&amp;width=785"
+							class="thickbox" title="lib/xmlsimple.rb">lib/xmlsimple.rb</a></li>
+					
+					</ul>
+				</div>
+			</div>
+
+			
+		</div>
+
+		<div id="class-metadata">
+
+			<!-- Parent Class -->
+			
+			<div id="parent-class-section" class="section">
+				<h3 class="section-header">Parent</h3>
+				
+				<p class="link">Object</p>
+				
+			</div>
+			
+
+			<!-- Namespace Contents -->
+			
+			<div id="namespace-list-section" class="section">
+				<h3 class="section-header">Namespace</h3>
+				<ul class="link-list">
+					
+					<li><span class="type">CLASS</span> <a href="XmlSimple/Cache.html">XmlSimple::Cache</a></li>
+					
+				</ul>
+			</div>
+			
+
+			<!-- Method Quickref -->
+			
+			<div id="method-list-section" class="section">
+				<h3 class="section-header">Methods</h3>
+				<ul class="link-list">
+					
+					<li><a href="#method-c-new">::new</a></li>
+					
+					<li><a href="#method-c-xml_in">::xml_in</a></li>
+					
+					<li><a href="#method-c-xml_out">::xml_out</a></li>
+					
+					<li><a href="#method-i-collapse">#collapse</a></li>
+					
+					<li><a href="#method-i-collapse_content">#collapse_content</a></li>
+					
+					<li><a href="#method-i-collapse_text_node">#collapse_text_node</a></li>
+					
+					<li><a href="#method-i-empty">#empty</a></li>
+					
+					<li><a href="#method-i-escape_value">#escape_value</a></li>
+					
+					<li><a href="#method-i-find_xml_file">#find_xml_file</a></li>
+					
+					<li><a href="#method-i-fold_array">#fold_array</a></li>
+					
+					<li><a href="#method-i-fold_array_by_name">#fold_array_by_name</a></li>
+					
+					<li><a href="#method-i-fold_arrays">#fold_arrays</a></li>
+					
+					<li><a href="#method-i-force_array%3F">#force_array?</a></li>
+					
+					<li><a href="#method-i-get_attributes">#get_attributes</a></li>
+					
+					<li><a href="#method-i-get_var">#get_var</a></li>
+					
+					<li><a href="#method-i-handle_options">#handle_options</a></li>
+					
+					<li><a href="#method-i-has_mixed_content%3F">#has_mixed_content?</a></li>
+					
+					<li><a href="#method-i-hash_to_array">#hash_to_array</a></li>
+					
+					<li><a href="#method-i-load_xml_file">#load_xml_file</a></li>
+					
+					<li><a href="#method-i-merge">#merge</a></li>
+					
+					<li><a href="#method-i-node_to_text">#node_to_text</a></li>
+					
+					<li><a href="#method-i-normalise_space">#normalise_space</a></li>
+					
+					<li><a href="#method-i-normalize_option_names">#normalize_option_names</a></li>
+					
+					<li><a href="#method-i-parse">#parse</a></li>
+					
+					<li><a href="#method-i-put_into_cache">#put_into_cache</a></li>
+					
+					<li><a href="#method-i-scalar">#scalar</a></li>
+					
+					<li><a href="#method-i-set_var">#set_var</a></li>
+					
+					<li><a href="#method-i-value_to_xml">#value_to_xml</a></li>
+					
+					<li><a href="#method-i-xml_in">#xml_in</a></li>
+					
+					<li><a href="#method-i-xml_out">#xml_out</a></li>
+					
+				</ul>
+			</div>
+			
+
+			<!-- Included Modules -->
+			
+			<div id="includes-section" class="section">
+				<h3 class="section-header">Included Modules</h3>
+				<ul class="link-list">
+				
+				
+					<li><span class="include">REXML</span></li>
+				
+				
+				</ul>
+			</div>
+			
+		</div>
+
+		<div id="project-metadata">
+			
+			
+
+			<div id="classindex-section" class="section project-section">
+				<h3 class="section-header">Class Index
+					<span class="search-toggle"><img src="./images/find.png"
+						height="16" width="16" alt="[+]"
+						title="show/hide quicksearch" /></span></h3>
+				<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
+				<fieldset>
+					<legend>Quicksearch</legend>
+					<input type="text" name="quicksearch" value=""
+						class="quicksearch-field" />
+				</fieldset>
+				</form>
+
+				<ul class="link-list">
+				
+					<li><a href="./XmlSimple.html">XmlSimple</a></li>
+				
+					<li><a href="./XmlSimple/Cache.html">XmlSimple::Cache</a></li>
+				
+				</ul>
+				<div id="no-class-search-results" style="display: none;">No matching classes.</div>
+			</div>
+
+			
+		</div>
+	</div>
+
+	<div id="documentation">
+		<h1 class="class">XmlSimple</h1>
+
+		<div id="description">
+			<p>
+Easy API to maintain XML (especially configuration files).
+</p>
+
+		</div>
+
+		<!-- Constants -->
+		
+		<div id="constants-list" class="section">
+			<h3 class="section-header">Constants</h3>
+			<dl>
+			
+				<dt><a name="KNOWN_OPTIONS">KNOWN_OPTIONS</a></dt>
+				
+				<dd class="description"><p>
+Declare options that are valid for <a
+href="XmlSimple.html#method-i-xml_in">xml_in</a> and xml_out.
+</p></dd>
+				
+			
+				<dt><a name="DEF_KEY_ATTRIBUTES">DEF_KEY_ATTRIBUTES</a></dt>
+				
+				<dd class="description"><p>
+Define some reasonable defaults.
+</p></dd>
+				
+			
+				<dt><a name="DEF_ROOT_NAME">DEF_ROOT_NAME</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+				<dt><a name="DEF_CONTENT_KEY">DEF_CONTENT_KEY</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+				<dt><a name="DEF_XML_DECLARATION">DEF_XML_DECLARATION</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+				<dt><a name="DEF_ANONYMOUS_TAG">DEF_ANONYMOUS_TAG</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+				<dt><a name="DEF_FORCE_ARRAY">DEF_FORCE_ARRAY</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+				<dt><a name="DEF_INDENTATION">DEF_INDENTATION</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+				<dt><a name="DEF_KEY_TO_SYMBOL">DEF_KEY_TO_SYMBOL</a></dt>
+				
+				<dd class="description"></dd>
+				
+			
+			</dl>
+		</div>
+		
+
+		<!-- Attributes -->
+		
+
+		<!-- Methods -->
+		
+		<div id="public-class-method-details" class="method-section section">
+			<h3 class="section-header">Public Class Methods</h3>
+
+		
+			<div id="new-method" class="method-detail ">
+				<a name="method-c-new"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">new</span><span
+						class="method-args">(defaults = nil)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Creates and intializes a new <a href="XmlSimple.html">XmlSimple</a> object.
+</p>
+<table>
+<tr><td valign="top">defaults</td><td><p>
+Default values for options.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="new-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 128</span>
+128:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">defaults</span> = <span class="ruby-keyword kw">nil</span>)
+129:     <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">defaults</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">||</span> <span class="ruby-identifier">defaults</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+130:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Options have to be a Hash.&quot;</span>
+131:     <span class="ruby-keyword kw">end</span>
+132:     <span class="ruby-ivar">@default_options</span> = <span class="ruby-identifier">normalize_option_names</span>(<span class="ruby-identifier">defaults</span>, (<span class="ruby-constant">KNOWN_OPTIONS</span>[<span class="ruby-value str">'in'</span>] <span class="ruby-operator">+</span> <span class="ruby-constant">KNOWN_OPTIONS</span>[<span class="ruby-value str">'out'</span>]).<span class="ruby-identifier">uniq</span>)
+133:     <span class="ruby-ivar">@options</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span>
+134:     <span class="ruby-ivar">@_var_values</span> = <span class="ruby-keyword kw">nil</span>
+135:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="xml-in-method" class="method-detail ">
+				<a name="method-c-xml_in"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">xml_in</span><span
+						class="method-args">(string = nil, options = nil)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+This is the functional version of the instance method xml_in.
+</p>
+					
+
+					
+					<div class="method-source-code"
+						id="xml-in-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 201</span>
+201:   <span class="ruby-keyword kw">def</span> <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">xml_in</span>(<span class="ruby-identifier">string</span> = <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+202:     <span class="ruby-identifier">xml_simple</span> = <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">new</span>
+203:     <span class="ruby-identifier">xml_simple</span>.<span class="ruby-identifier">xml_in</span>(<span class="ruby-identifier">string</span>, <span class="ruby-identifier">options</span>)
+204:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="xml-out-method" class="method-detail ">
+				<a name="method-c-xml_out"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">xml_out</span><span
+						class="method-args">(hash, options = nil)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+This is the functional version of the instance method xml_out.
+</p>
+					
+
+					
+					<div class="method-source-code"
+						id="xml-out-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 257</span>
+257:   <span class="ruby-keyword kw">def</span> <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">xml_out</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+258:     <span class="ruby-identifier">xml_simple</span> = <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">new</span>
+259:     <span class="ruby-identifier">xml_simple</span>.<span class="ruby-identifier">xml_out</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-identifier">options</span>)
+260:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+		</div>
+	
+		<div id="public-instance-method-details" class="method-section section">
+			<h3 class="section-header">Public Instance Methods</h3>
+
+		
+			<div id="xml-in-method" class="method-detail ">
+				<a name="method-i-xml_in"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">xml_in</span><span
+						class="method-args">(string = nil, options = nil)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Converts an XML document in the same way as the Perl module XML::Simple.
+</p>
+<table>
+<tr><td valign="top">string</td><td><p>
+XML source. Could be one of the following:
+</p>
+<ul>
+<li><p>
+nil: Tries to load and parse &#8217;<scriptname>.xml&#8217;.
+</p>
+</li>
+</ul>
+<ul>
+<li><p>
+filename: Tries to load and parse filename.
+</p>
+</li>
+</ul>
+<ul>
+<li><p>
+IO object: Reads from object until EOF is detected and parses result.
+</p>
+</li>
+</ul>
+<ul>
+<li><p>
+XML string: Parses string.
+</p>
+</li>
+</ul>
+</td></tr>
+<tr><td valign="top">options</td><td><p>
+Options to be used.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="xml-in-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 149</span>
+149:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">xml_in</span>(<span class="ruby-identifier">string</span> = <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+150:     <span class="ruby-identifier">handle_options</span>(<span class="ruby-value str">'in'</span>, <span class="ruby-identifier">options</span>)
+151: 
+152:     <span class="ruby-comment cmt"># If no XML string or filename was supplied look for scriptname.xml.</span>
+153:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">nil?</span>
+154:       <span class="ruby-identifier">string</span> = <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">basename</span>(<span class="ruby-identifier">$0</span>).<span class="ruby-identifier">dup</span>
+155:       <span class="ruby-identifier">string</span>.<span class="ruby-identifier">sub!</span>(<span class="ruby-regexp re">/\.[^.]+$/</span>, <span class="ruby-value str">''</span>)
+156:       <span class="ruby-identifier">string</span> <span class="ruby-operator">+=</span> <span class="ruby-value str">'.xml'</span>
+157: 
+158:       <span class="ruby-identifier">directory</span> = <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">dirname</span>(<span class="ruby-identifier">$0</span>)
+159:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>].<span class="ruby-identifier">unshift</span>(<span class="ruby-identifier">directory</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">directory</span>.<span class="ruby-identifier">nil?</span>
+160:     <span class="ruby-keyword kw">end</span>
+161: 
+162:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">String</span>)
+163:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">string</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/&lt;.*?&gt;/</span>
+164:         <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">string</span>)
+165:       <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">string</span> <span class="ruby-operator">==</span> <span class="ruby-value str">'-'</span>
+166:         <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">$stdin</span>.<span class="ruby-identifier">read</span>)
+167:       <span class="ruby-keyword kw">else</span>
+168:         <span class="ruby-identifier">filename</span> = <span class="ruby-identifier">find_xml_file</span>(<span class="ruby-identifier">string</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>])
+169: 
+170:         <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'cache'</span>)
+171:           <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'cache'</span>].<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">scheme</span><span class="ruby-operator">|</span>
+172:             <span class="ruby-keyword kw">case</span>(<span class="ruby-identifier">scheme</span>)
+173:             <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'storable'</span>
+174:               <span class="ruby-identifier">content</span> = <span class="ruby-identifier">@@cache</span>.<span class="ruby-identifier">restore_storable</span>(<span class="ruby-identifier">filename</span>)
+175:             <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'mem_share'</span>
+176:               <span class="ruby-identifier">content</span> = <span class="ruby-identifier">@@cache</span>.<span class="ruby-identifier">restore_mem_share</span>(<span class="ruby-identifier">filename</span>)
+177:             <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'mem_copy'</span>
+178:               <span class="ruby-identifier">content</span> = <span class="ruby-identifier">@@cache</span>.<span class="ruby-identifier">restore_mem_copy</span>(<span class="ruby-identifier">filename</span>)
+179:             <span class="ruby-keyword kw">else</span>
+180:               <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Unsupported caching scheme: &lt;#{scheme}&gt;.&quot;</span>
+181:             <span class="ruby-keyword kw">end</span>
+182:             <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">content</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">content</span>
+183:           }
+184:         <span class="ruby-keyword kw">end</span>
+185:         
+186:         <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">load_xml_file</span>(<span class="ruby-identifier">filename</span>)
+187:       <span class="ruby-keyword kw">end</span>
+188:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">IO</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">StringIO</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">Zlib</span><span class="ruby-operator">::</span><span class="ruby-constant">GzipReader</span>)
+189:       <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">string</span>.<span class="ruby-identifier">read</span>)
+190:     <span class="ruby-keyword kw">else</span>
+191:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Could not parse object of type: &lt;#{string.type}&gt;.&quot;</span>
+192:     <span class="ruby-keyword kw">end</span>
+193: 
+194:     <span class="ruby-identifier">result</span> = <span class="ruby-identifier">collapse</span>(<span class="ruby-ivar">@doc</span>.<span class="ruby-identifier">root</span>)
+195:     <span class="ruby-identifier">result</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keeproot'</span>] <span class="ruby-operator">?</span> <span class="ruby-identifier">merge</span>({}, <span class="ruby-ivar">@doc</span>.<span class="ruby-identifier">root</span>.<span class="ruby-identifier">name</span>, <span class="ruby-identifier">result</span>) <span class="ruby-operator">:</span> <span class="ruby-identifier">result</span>
+196:     <span class="ruby-identifier">put_into_cache</span>(<span class="ruby-identifier">result</span>, <span class="ruby-identifier">filename</span>)
+197:     <span class="ruby-identifier">result</span>
+198:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="xml-out-method" class="method-detail ">
+				<a name="method-i-xml_out"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">xml_out</span><span
+						class="method-args">(ref, options = nil)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Converts a data structure into an XML document.
+</p>
+<table>
+<tr><td valign="top">ref</td><td><p>
+Reference to data structure to be converted into XML.
+</p>
+</td></tr>
+<tr><td valign="top">options</td><td><p>
+Options to be used.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="xml-out-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 212</span>
+212:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">xml_out</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+213:     <span class="ruby-identifier">handle_options</span>(<span class="ruby-value str">'out'</span>, <span class="ruby-identifier">options</span>)
+214:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+215:       <span class="ruby-identifier">ref</span> = { <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'anonymoustag'</span>] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">ref</span> }
+216:     <span class="ruby-keyword kw">end</span>
+217: 
+218:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keeproot'</span>]
+219:       <span class="ruby-identifier">keys</span> = <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">keys</span>
+220:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">keys</span>.<span class="ruby-identifier">size</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span>
+221:         <span class="ruby-identifier">ref</span> = <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">keys</span>[<span class="ruby-value">0</span>]]
+222:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>] = <span class="ruby-identifier">keys</span>[<span class="ruby-value">0</span>]
+223:       <span class="ruby-keyword kw">end</span>
+224:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>] <span class="ruby-operator">==</span> <span class="ruby-value str">''</span>
+225:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+226:         <span class="ruby-identifier">refsave</span> = <span class="ruby-identifier">ref</span>
+227:         <span class="ruby-identifier">ref</span> = {}
+228:         <span class="ruby-identifier">refsave</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+229:           <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">value</span>)
+230:             <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span>
+231:           <span class="ruby-keyword kw">else</span>
+232:             <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">key</span>] = [ <span class="ruby-identifier">value</span>.<span class="ruby-identifier">to_s</span> ]
+233:           <span class="ruby-keyword kw">end</span>
+234:         }
+235:       <span class="ruby-keyword kw">end</span>
+236:     <span class="ruby-keyword kw">end</span>
+237: 
+238:     <span class="ruby-ivar">@ancestors</span> = []
+239:     <span class="ruby-identifier">xml</span> = <span class="ruby-identifier">value_to_xml</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>], <span class="ruby-value str">''</span>)
+240:     <span class="ruby-ivar">@ancestors</span> = <span class="ruby-keyword kw">nil</span>
+241: 
+242:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'xmldeclaration'</span>]
+243:       <span class="ruby-identifier">xml</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'xmldeclaration'</span>] <span class="ruby-operator">+</span> <span class="ruby-value str">&quot;\n&quot;</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">xml</span>
+244:     <span class="ruby-keyword kw">end</span>
+245: 
+246:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'outputfile'</span>)
+247:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'outputfile'</span>].<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">IO</span>)
+248:         <span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'outputfile'</span>].<span class="ruby-identifier">write</span>(<span class="ruby-identifier">xml</span>)
+249:       <span class="ruby-keyword kw">else</span>
+250:         <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'outputfile'</span>], <span class="ruby-value str">&quot;w&quot;</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">file</span><span class="ruby-operator">|</span> <span class="ruby-identifier">file</span>.<span class="ruby-identifier">write</span>(<span class="ruby-identifier">xml</span>) }
+251:       <span class="ruby-keyword kw">end</span>
+252:     <span class="ruby-keyword kw">end</span>
+253:     <span class="ruby-identifier">xml</span>
+254:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+		</div>
+	
+		<div id="private-instance-method-details" class="method-section section">
+			<h3 class="section-header">Private Instance Methods</h3>
+
+		
+			<div id="collapse-method" class="method-detail ">
+				<a name="method-i-collapse"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">collapse</span><span
+						class="method-args">(element)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Actually converts an XML document element into a data structure.
+</p>
+<table>
+<tr><td valign="top">element</td><td><p>
+The document element to be collapsed.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="collapse-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 461</span>
+461:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">collapse</span>(<span class="ruby-identifier">element</span>)
+462:     <span class="ruby-identifier">result</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noattr'</span>] <span class="ruby-operator">?</span> {} <span class="ruby-operator">:</span> <span class="ruby-identifier">get_attributes</span>(<span class="ruby-identifier">element</span>)
+463: 
+464:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>] <span class="ruby-operator">==</span> <span class="ruby-value">2</span>
+465:       <span class="ruby-identifier">result</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">k</span>, <span class="ruby-identifier">v</span><span class="ruby-operator">|</span> <span class="ruby-identifier">result</span>[<span class="ruby-identifier">k</span>] = <span class="ruby-identifier">normalise_space</span>(<span class="ruby-identifier">v</span>) }
+466:     <span class="ruby-keyword kw">end</span>
+467: 
+468:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">element</span>.<span class="ruby-identifier">has_elements?</span>
+469:       <span class="ruby-identifier">element</span>.<span class="ruby-identifier">each_element</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">child</span><span class="ruby-operator">|</span>
+470:         <span class="ruby-identifier">value</span> = <span class="ruby-identifier">collapse</span>(<span class="ruby-identifier">child</span>)
+471:         <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">empty</span>(<span class="ruby-identifier">value</span>) <span class="ruby-operator">&amp;&amp;</span> (<span class="ruby-identifier">element</span>.<span class="ruby-identifier">attributes</span>.<span class="ruby-identifier">empty?</span> <span class="ruby-operator">||</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noattr'</span>])
+472:           <span class="ruby-keyword kw">next</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'suppressempty'</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'suppressempty'</span>] <span class="ruby-operator">==</span> <span class="ruby-keyword kw">true</span>
+473:         <span class="ruby-keyword kw">end</span>
+474:         <span class="ruby-identifier">result</span> = <span class="ruby-identifier">merge</span>(<span class="ruby-identifier">result</span>, <span class="ruby-identifier">child</span>.<span class="ruby-identifier">name</span>, <span class="ruby-identifier">value</span>)
+475:       }
+476:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">has_mixed_content?</span>(<span class="ruby-identifier">element</span>)
+477:         <span class="ruby-comment cmt"># normalisespace?</span>
+478:         <span class="ruby-identifier">content</span> = <span class="ruby-identifier">element</span>.<span class="ruby-identifier">texts</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">x</span><span class="ruby-operator">|</span> <span class="ruby-identifier">x</span>.<span class="ruby-identifier">to_s</span> }
+479:         <span class="ruby-identifier">content</span> = <span class="ruby-identifier">content</span>[<span class="ruby-value">0</span>] <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">content</span>.<span class="ruby-identifier">size</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span>
+480:         <span class="ruby-identifier">result</span>[<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>]] = <span class="ruby-identifier">content</span>
+481:       <span class="ruby-keyword kw">end</span>
+482:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">element</span>.<span class="ruby-identifier">has_text?</span> <span class="ruby-comment cmt"># i.e. it has only text.</span>
+483:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">collapse_text_node</span>(<span class="ruby-identifier">result</span>, <span class="ruby-identifier">element</span>)
+484:     <span class="ruby-keyword kw">end</span>
+485: 
+486:     <span class="ruby-comment cmt"># Turn Arrays into Hashes if key fields present.</span>
+487:     <span class="ruby-identifier">count</span> = <span class="ruby-identifier">fold_arrays</span>(<span class="ruby-identifier">result</span>)
+488: 
+489:     <span class="ruby-comment cmt"># Disintermediate grouped tags.</span>
+490:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'grouptags'</span>)
+491:       <span class="ruby-identifier">result</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+492:         <span class="ruby-keyword kw">next</span> <span class="ruby-keyword kw">unless</span> (<span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">&amp;&amp;</span> (<span class="ruby-identifier">value</span>.<span class="ruby-identifier">size</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span>))
+493:         <span class="ruby-identifier">child_key</span>, <span class="ruby-identifier">child_value</span> = <span class="ruby-identifier">value</span>.<span class="ruby-identifier">to_a</span>[<span class="ruby-value">0</span>]
+494:         <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'grouptags'</span>][<span class="ruby-identifier">key</span>] <span class="ruby-operator">==</span> <span class="ruby-identifier">child_key</span>
+495:           <span class="ruby-identifier">result</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">child_value</span>
+496:         <span class="ruby-keyword kw">end</span>
+497:       }
+498:     <span class="ruby-keyword kw">end</span>
+499:     
+500:     <span class="ruby-comment cmt"># Fold Hashes containing a single anonymous Array up into just the Array.</span>
+501:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">count</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span> 
+502:       <span class="ruby-identifier">anonymoustag</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'anonymoustag'</span>]
+503:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">result</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">anonymoustag</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">result</span>[<span class="ruby-identifier">anonymoustag</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+504:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">result</span>[<span class="ruby-identifier">anonymoustag</span>]
+505:       <span class="ruby-keyword kw">end</span>
+506:     <span class="ruby-keyword kw">end</span>
+507: 
+508:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">result</span>.<span class="ruby-identifier">empty?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'suppressempty'</span>)
+509:       <span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'suppressempty'</span>] <span class="ruby-operator">==</span> <span class="ruby-value str">''</span> <span class="ruby-operator">?</span> <span class="ruby-value str">''</span> <span class="ruby-operator">:</span> <span class="ruby-keyword kw">nil</span>
+510:     <span class="ruby-keyword kw">end</span>
+511: 
+512:     <span class="ruby-identifier">result</span>
+513:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="collapse-content-method" class="method-detail ">
+				<a name="method-i-collapse_content"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">collapse_content</span><span
+						class="method-args">(hash)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Tries to collapse a Hash even more ;-)
+</p>
+<table>
+<tr><td valign="top">hash</td><td><p>
+Hash to be collapsed again.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="collapse-content-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 624</span>
+624:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">collapse_content</span>(<span class="ruby-identifier">hash</span>)
+625:     <span class="ruby-identifier">content_key</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>]
+626:     <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">each_value</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+627:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">hash</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">size</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">content_key</span>)
+628:       <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">each_key</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span><span class="ruby-operator">|</span> <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>][<span class="ruby-identifier">content_key</span>] }
+629:     }
+630:     <span class="ruby-identifier">hash</span>
+631:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="collapse-text-node-method" class="method-detail ">
+				<a name="method-i-collapse_text_node"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">collapse_text_node</span><span
+						class="method-args">(hash, element)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Collapses a text node and merges it with an existing Hash, if possible.
+Thanks to Curtis Schofield for reporting a subtle bug.
+</p>
+<table>
+<tr><td valign="top">hash</td><td><p>
+Hash to merge text node value with, if possible.
+</p>
+</td></tr>
+<tr><td valign="top">element</td><td><p>
+Text node to be collapsed.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="collapse-text-node-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 523</span>
+523:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">collapse_text_node</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-identifier">element</span>)
+524:     <span class="ruby-identifier">value</span> = <span class="ruby-identifier">node_to_text</span>(<span class="ruby-identifier">element</span>)
+525:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">empty</span>(<span class="ruby-identifier">value</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-identifier">element</span>.<span class="ruby-identifier">has_attributes?</span>
+526:       <span class="ruby-keyword kw">return</span> {}
+527:     <span class="ruby-keyword kw">end</span>
+528: 
+529:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">element</span>.<span class="ruby-identifier">has_attributes?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noattr'</span>]
+530:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">merge</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>], <span class="ruby-identifier">value</span>)
+531:     <span class="ruby-keyword kw">else</span>
+532:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcecontent'</span>]
+533:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">merge</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>], <span class="ruby-identifier">value</span>)
+534:       <span class="ruby-keyword kw">else</span>
+535:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">value</span>
+536:       <span class="ruby-keyword kw">end</span>
+537:     <span class="ruby-keyword kw">end</span>
+538:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="empty-method" class="method-detail ">
+				<a name="method-i-empty"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">empty</span><span
+						class="method-args">(value)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Checks, if an object is nil, an empty String or an empty Hash. Thanks to
+Norbert Gawor for a bugfix.
+</p>
+<table>
+<tr><td valign="top">value</td><td><p>
+Value to be checked for emptyness.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="empty-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 918</span>
+918:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">empty</span>(<span class="ruby-identifier">value</span>)
+919:     <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">value</span>
+920:       <span class="ruby-keyword kw">when</span> <span class="ruby-constant">Hash</span>
+921:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">empty?</span>
+922:       <span class="ruby-keyword kw">when</span> <span class="ruby-constant">String</span>
+923:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">value</span> <span class="ruby-operator">!~</span> <span class="ruby-regexp re">/\S/</span>
+924:       <span class="ruby-keyword kw">else</span>
+925:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">nil?</span>
+926:     <span class="ruby-keyword kw">end</span>
+927:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="escape-value-method" class="method-detail ">
+				<a name="method-i-escape_value"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">escape_value</span><span
+						class="method-args">(data)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Replaces XML markup characters by their external entities.
+</p>
+<table>
+<tr><td valign="top">data</td><td><p>
+The string to be escaped.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="escape-value-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 900</span>
+900:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">escape_value</span>(<span class="ruby-identifier">data</span>)
+901:     <span class="ruby-constant">Text</span><span class="ruby-operator">::</span><span class="ruby-identifier">normalize</span>(<span class="ruby-identifier">data</span>)
+902:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="find-xml-file-method" class="method-detail ">
+				<a name="method-i-find_xml_file"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">find_xml_file</span><span
+						class="method-args">(file, searchpath)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Searches in a list of paths for a certain file. Returns the full path to
+the file, if it could be found. Otherwise, an exception will be raised.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Name of the file to search for.
+</p>
+</td></tr>
+<tr><td valign="top">searchpath</td><td><p>
+List of paths to search in.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="find-xml-file-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 970</span>
+970:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">find_xml_file</span>(<span class="ruby-identifier">file</span>, <span class="ruby-identifier">searchpath</span>)
+971:     <span class="ruby-identifier">filename</span> = <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">basename</span>(<span class="ruby-identifier">file</span>)
+972: 
+973:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">filename</span> <span class="ruby-operator">!=</span> <span class="ruby-identifier">file</span>
+974:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">file</span> <span class="ruby-keyword kw">if</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">file?</span>(<span class="ruby-identifier">file</span>)
+975:     <span class="ruby-keyword kw">else</span>
+976:       <span class="ruby-identifier">searchpath</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">path</span><span class="ruby-operator">|</span>
+977:         <span class="ruby-identifier">full_path</span> = <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">join</span>(<span class="ruby-identifier">path</span>, <span class="ruby-identifier">filename</span>)
+978:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">full_path</span> <span class="ruby-keyword kw">if</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">file?</span>(<span class="ruby-identifier">full_path</span>)
+979:       }
+980:     <span class="ruby-keyword kw">end</span>
+981: 
+982:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">searchpath</span>.<span class="ruby-identifier">empty?</span>
+983:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">file</span> <span class="ruby-keyword kw">if</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">file?</span>(<span class="ruby-identifier">file</span>)
+984:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;File does not exist: #{file}.&quot;</span>
+985:     <span class="ruby-keyword kw">end</span>
+986:     <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Could not find &lt;#{filename}&gt; in &lt;#{searchpath.join(':')}&gt;&quot;</span>
+987:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="fold-array-method" class="method-detail ">
+				<a name="method-i-fold_array"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">fold_array</span><span
+						class="method-args">(array)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Folds an Array to a Hash, if possible. Folding happens according to the
+content of keyattr, which has to be an array.
+</p>
+<table>
+<tr><td valign="top">array</td><td><p>
+Array to be folded.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="fold-array-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 568</span>
+568:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">fold_array</span>(<span class="ruby-identifier">array</span>)
+569:     <span class="ruby-identifier">hash</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span>
+570:     <span class="ruby-identifier">array</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">x</span><span class="ruby-operator">|</span>
+571:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">array</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">x</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+572:       <span class="ruby-identifier">key_matched</span> = <span class="ruby-keyword kw">false</span>
+573:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span><span class="ruby-operator">|</span>
+574:         <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">x</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">key</span>)
+575:           <span class="ruby-identifier">key_matched</span> = <span class="ruby-keyword kw">true</span>
+576:           <span class="ruby-identifier">value</span> = <span class="ruby-identifier">x</span>[<span class="ruby-identifier">key</span>]
+577:           <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">array</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+578:           <span class="ruby-identifier">value</span> = <span class="ruby-identifier">normalise_space</span>(<span class="ruby-identifier">value</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>] <span class="ruby-operator">==</span> <span class="ruby-value">1</span>
+579:           <span class="ruby-identifier">x</span>.<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">key</span>)
+580:           <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">value</span>] = <span class="ruby-identifier">x</span>
+581:           <span class="ruby-keyword kw">break</span>
+582:         <span class="ruby-keyword kw">end</span>
+583:       }
+584:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">array</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">key_matched</span>
+585:     }
+586:     <span class="ruby-identifier">hash</span> = <span class="ruby-identifier">collapse_content</span>(<span class="ruby-identifier">hash</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'collapseagain'</span>]
+587:     <span class="ruby-identifier">hash</span>
+588:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="fold-array-by-name-method" class="method-detail ">
+				<a name="method-i-fold_array_by_name"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">fold_array_by_name</span><span
+						class="method-args">(name, array)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Folds an Array to a Hash, if possible. Folding happens according to the
+content of keyattr, which has to be a Hash.
+</p>
+<table>
+<tr><td valign="top">name</td><td><p>
+Name of the attribute to be folded upon.
+</p>
+</td></tr>
+<tr><td valign="top">array</td><td><p>
+Array to be folded.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="fold-array-by-name-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 598</span>
+598:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">fold_array_by_name</span>(<span class="ruby-identifier">name</span>, <span class="ruby-identifier">array</span>)
+599:     <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">array</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">name</span>)
+600:     <span class="ruby-identifier">key</span>, <span class="ruby-identifier">flag</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>][<span class="ruby-identifier">name</span>]
+601: 
+602:     <span class="ruby-identifier">hash</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span>
+603:     <span class="ruby-identifier">array</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">x</span><span class="ruby-operator">|</span>
+604:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">x</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">x</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">key</span>)
+605:         <span class="ruby-identifier">value</span> = <span class="ruby-identifier">x</span>[<span class="ruby-identifier">key</span>]
+606:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">array</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+607:         <span class="ruby-identifier">value</span> = <span class="ruby-identifier">normalise_space</span>(<span class="ruby-identifier">value</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>] <span class="ruby-operator">==</span> <span class="ruby-value">1</span>
+608:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">value</span>] = <span class="ruby-identifier">x</span>
+609:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">value</span>][<span class="ruby-node">&quot;-#{key}&quot;</span>] = <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">value</span>][<span class="ruby-identifier">key</span>] <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">flag</span> <span class="ruby-operator">==</span> <span class="ruby-value str">'-'</span>
+610:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">value</span>].<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">key</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">flag</span> <span class="ruby-operator">==</span> <span class="ruby-value str">'+'</span>
+611:       <span class="ruby-keyword kw">else</span>
+612:         <span class="ruby-identifier">$stderr</span>.<span class="ruby-identifier">puts</span>(<span class="ruby-node">&quot;Warning: &lt;#{name}&gt; element has no '#{key}' attribute.&quot;</span>)
+613:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">array</span>
+614:       <span class="ruby-keyword kw">end</span>
+615:     }
+616:     <span class="ruby-identifier">hash</span> = <span class="ruby-identifier">collapse_content</span>(<span class="ruby-identifier">hash</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'collapseagain'</span>]
+617:     <span class="ruby-identifier">hash</span>
+618:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="fold-arrays-method" class="method-detail ">
+				<a name="method-i-fold_arrays"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">fold_arrays</span><span
+						class="method-args">(hash)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Folds all arrays in a Hash.
+</p>
+<table>
+<tr><td valign="top">hash</td><td><p>
+Hash to be folded.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="fold-arrays-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 544</span>
+544:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">fold_arrays</span>(<span class="ruby-identifier">hash</span>)
+545:     <span class="ruby-identifier">fold_amount</span> = <span class="ruby-value">0</span>
+546:     <span class="ruby-identifier">keyattr</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>]
+547:     <span class="ruby-keyword kw">if</span> (<span class="ruby-identifier">keyattr</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">keyattr</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>))
+548:       <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+549:         <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+550:           <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">keyattr</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+551:             <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">fold_array</span>(<span class="ruby-identifier">value</span>)
+552:           <span class="ruby-keyword kw">else</span>
+553:             <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">fold_array_by_name</span>(<span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span>)
+554:           <span class="ruby-keyword kw">end</span>
+555:           <span class="ruby-identifier">fold_amount</span> <span class="ruby-operator">+=</span> <span class="ruby-value">1</span>
+556:         <span class="ruby-keyword kw">end</span>
+557:       }
+558:     <span class="ruby-keyword kw">end</span>
+559:     <span class="ruby-identifier">fold_amount</span>
+560:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="force-array--method" class="method-detail ">
+				<a name="method-i-force_array%3F"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">force_array?</span><span
+						class="method-args">(key)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Checks, if the &#8216;forcearray&#8217; option has to be used for a certain
+key.
+</p>
+					
+
+					
+					<div class="method-source-code"
+						id="force-array--source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 689</span>
+689:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">force_array?</span>(<span class="ruby-identifier">key</span>)
+690:     <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">false</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">key</span> <span class="ruby-operator">==</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>]
+691:     <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] <span class="ruby-operator">==</span> <span class="ruby-keyword kw">true</span>
+692:     <span class="ruby-identifier">forcearray</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>]
+693:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">forcearray</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+694:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">forcearray</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">key</span>) 
+695:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">false</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">forcearray</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'_regex'</span>)
+696:       <span class="ruby-identifier">forcearray</span>[<span class="ruby-value str">'_regex'</span>].<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">x</span><span class="ruby-operator">|</span> <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">key</span> <span class="ruby-operator">=~</span> <span class="ruby-identifier">x</span> }
+697:     <span class="ruby-keyword kw">end</span>
+698:     <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">false</span>
+699:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="get-attributes-method" class="method-detail ">
+				<a name="method-i-get_attributes"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">get_attributes</span><span
+						class="method-args">(node)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Converts the attributes array of a document node into a Hash. Returns an
+empty Hash, if node has no attributes.
+</p>
+<table>
+<tr><td valign="top">node</td><td><p>
+Document node to extract attributes from.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="get-attributes-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 706</span>
+706:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">get_attributes</span>(<span class="ruby-identifier">node</span>)
+707:     <span class="ruby-identifier">attributes</span> = {}
+708:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'attrprefix'</span>]
+709:       <span class="ruby-identifier">node</span>.<span class="ruby-identifier">attributes</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">n</span>,<span class="ruby-identifier">v</span><span class="ruby-operator">|</span> <span class="ruby-identifier">attributes</span>[<span class="ruby-value str">&quot;@&quot;</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">n</span>] = <span class="ruby-identifier">v</span> }
+710:     <span class="ruby-keyword kw">else</span>
+711:       <span class="ruby-identifier">node</span>.<span class="ruby-identifier">attributes</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">n</span>,<span class="ruby-identifier">v</span><span class="ruby-operator">|</span> <span class="ruby-identifier">attributes</span>[<span class="ruby-identifier">n</span>] = <span class="ruby-identifier">v</span> }
+712:     <span class="ruby-keyword kw">end</span>
+713:     <span class="ruby-identifier">attributes</span>
+714:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="get-var-method" class="method-detail ">
+				<a name="method-i-get_var"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">get_var</span><span
+						class="method-args">(name)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Called during variable substitution to get the value for the named
+variable.
+</p>
+					
+
+					
+					<div class="method-source-code"
+						id="get-var-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 737</span>
+737:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">get_var</span>(<span class="ruby-identifier">name</span>)
+738:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@_var_values</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">name</span>)
+739:       <span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@_var_values</span>[<span class="ruby-identifier">name</span>]
+740:     <span class="ruby-keyword kw">else</span>
+741:       <span class="ruby-keyword kw">return</span> <span class="ruby-node">&quot;${#{name}}&quot;</span>
+742:     <span class="ruby-keyword kw">end</span>
+743:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="handle-options-method" class="method-detail ">
+				<a name="method-i-handle_options"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">handle_options</span><span
+						class="method-args">(direction, options)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Merges a set of options with the default options.
+</p>
+<table>
+<tr><td valign="top">direction</td><td><p>
+&#8216;in&#8217;:  If options should be handled for xml_in.
+&#8216;out&#8217;: If options should be handled for xml_out.
+</p>
+</td></tr>
+<tr><td valign="top">options</td><td><p>
+Options to be merged with the default options.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="handle-options-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 319</span>
+319:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">handle_options</span>(<span class="ruby-identifier">direction</span>, <span class="ruby-identifier">options</span>)
+320:     <span class="ruby-ivar">@options</span> = <span class="ruby-identifier">options</span> <span class="ruby-operator">||</span> <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span>
+321: 
+322:     <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Options must be a Hash!&quot;</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+323: 
+324:     <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">KNOWN_OPTIONS</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">direction</span>)
+325:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Unknown direction: &lt;#{direction}&gt;.&quot;</span>
+326:     <span class="ruby-keyword kw">end</span>
+327: 
+328:     <span class="ruby-identifier">known_options</span> = <span class="ruby-constant">KNOWN_OPTIONS</span>[<span class="ruby-identifier">direction</span>]
+329:     <span class="ruby-ivar">@options</span> = <span class="ruby-identifier">normalize_option_names</span>(<span class="ruby-ivar">@options</span>, <span class="ruby-identifier">known_options</span>)
+330: 
+331:     <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@default_options</span>.<span class="ruby-identifier">nil?</span>
+332:       <span class="ruby-identifier">known_options</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">option</span><span class="ruby-operator">|</span>
+333:         <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">option</span>)
+334:           <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@default_options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">option</span>)
+335:             <span class="ruby-ivar">@options</span>[<span class="ruby-identifier">option</span>] = <span class="ruby-ivar">@default_options</span>[<span class="ruby-identifier">option</span>]
+336:           <span class="ruby-keyword kw">end</span>
+337:         <span class="ruby-keyword kw">end</span>
+338:       }
+339:     <span class="ruby-keyword kw">end</span>
+340: 
+341:     <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'noattr'</span>)
+342:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noattr'</span>] = <span class="ruby-keyword kw">false</span>
+343:     <span class="ruby-keyword kw">end</span>
+344: 
+345:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'rootname'</span>)
+346:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>] = <span class="ruby-value str">''</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>].<span class="ruby-identifier">nil?</span>
+347:     <span class="ruby-keyword kw">else</span>
+348:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>] = <span class="ruby-constant">DEF_ROOT_NAME</span>
+349:     <span class="ruby-keyword kw">end</span>
+350: 
+351:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'xmldeclaration'</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'xmldeclaration'</span>] <span class="ruby-operator">==</span> <span class="ruby-keyword kw">true</span>
+352:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'xmldeclaration'</span>] = <span class="ruby-constant">DEF_XML_DECLARATION</span>
+353:     <span class="ruby-keyword kw">end</span>
+354: 
+355:     <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keytosymbol'</span>] = <span class="ruby-constant">DEF_KEY_TO_SYMBOL</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'keytosymbol'</span>)
+356: 
+357:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'contentkey'</span>)
+358:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>] <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/^-(.*)$/</span>
+359:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>]    = <span class="ruby-node">$1</span>
+360:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'collapseagain'</span>] = <span class="ruby-keyword kw">true</span>
+361:       <span class="ruby-keyword kw">end</span>
+362:     <span class="ruby-keyword kw">else</span>
+363:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>] = <span class="ruby-constant">DEF_CONTENT_KEY</span>
+364:     <span class="ruby-keyword kw">end</span>
+365: 
+366:     <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'normalisespace'</span>)
+367:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>] = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalizespace'</span>]
+368:     <span class="ruby-keyword kw">end</span>
+369:     <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>] = <span class="ruby-value">0</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>].<span class="ruby-identifier">nil?</span>
+370: 
+371:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'searchpath'</span>)
+372:       <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+373:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>] = [ <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>] ]
+374:       <span class="ruby-keyword kw">end</span>
+375:     <span class="ruby-keyword kw">else</span>
+376:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>] = []
+377:     <span class="ruby-keyword kw">end</span>
+378: 
+379:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'cache'</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">scalar</span>(<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'cache'</span>])
+380:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'cache'</span>] = [ <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'cache'</span>] ]
+381:     <span class="ruby-keyword kw">end</span>
+382: 
+383:     <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'anonymoustag'</span>] = <span class="ruby-constant">DEF_ANONYMOUS_TAG</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'anonymoustag'</span>)
+384: 
+385:     <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'indent'</span>) <span class="ruby-operator">||</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'indent'</span>].<span class="ruby-identifier">nil?</span>
+386:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'indent'</span>] = <span class="ruby-constant">DEF_INDENTATION</span>
+387:     <span class="ruby-keyword kw">end</span>
+388: 
+389:     <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'indent'</span>] = <span class="ruby-value str">''</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'noindent'</span>)
+390: 
+391:     <span class="ruby-comment cmt"># Special cleanup for 'keyattr' which could be an array or</span>
+392:     <span class="ruby-comment cmt"># a hash or left to default to array.</span>
+393:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'keyattr'</span>)
+394:       <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">scalar</span>(<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>])
+395:         <span class="ruby-comment cmt"># Convert keyattr =&gt; { elem =&gt; '+attr' }</span>
+396:         <span class="ruby-comment cmt">#      to keyattr =&gt; { elem =&gt; ['attr', '+'] }</span>
+397:         <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+398:           <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+399:             <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/^([-+])?(.*)$/</span>
+400:               <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>][<span class="ruby-identifier">key</span>] = [<span class="ruby-node">$2</span>, <span class="ruby-node">$1</span> <span class="ruby-operator">?</span> <span class="ruby-node">$1</span> <span class="ruby-operator">:</span> <span class="ruby-value str">''</span>]
+401:             <span class="ruby-keyword kw">end</span>
+402:           }
+403:         <span class="ruby-keyword kw">elsif</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+404:           <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;'keyattr' must be String, Hash, or Array!&quot;</span>
+405:         <span class="ruby-keyword kw">end</span>
+406:       <span class="ruby-keyword kw">else</span>
+407:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>] = [ <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>] ]
+408:       <span class="ruby-keyword kw">end</span>
+409:     <span class="ruby-keyword kw">else</span>
+410:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>] = <span class="ruby-constant">DEF_KEY_ATTRIBUTES</span>
+411:     <span class="ruby-keyword kw">end</span>
+412: 
+413:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'forcearray'</span>)
+414:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Regexp</span>)
+415:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] = [ <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] ]
+416:       <span class="ruby-keyword kw">end</span>
+417: 
+418:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+419:         <span class="ruby-identifier">force_list</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>]
+420:         <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">force_list</span>.<span class="ruby-identifier">empty?</span>
+421:           <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] = {}
+422:           <span class="ruby-identifier">force_list</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">tag</span><span class="ruby-operator">|</span>
+423:             <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">tag</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Regexp</span>)
+424:               <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>][<span class="ruby-value str">'_regex'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+425:                 <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>][<span class="ruby-value str">'_regex'</span>] = []
+426:               <span class="ruby-keyword kw">end</span>
+427:               <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>][<span class="ruby-value str">'_regex'</span>] <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">tag</span>
+428:             <span class="ruby-keyword kw">else</span>
+429:               <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>][<span class="ruby-identifier">tag</span>] = <span class="ruby-keyword kw">true</span>
+430:             <span class="ruby-keyword kw">end</span>
+431:           }
+432:         <span class="ruby-keyword kw">else</span>
+433:           <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] = <span class="ruby-keyword kw">false</span>
+434:         <span class="ruby-keyword kw">end</span>
+435:       <span class="ruby-keyword kw">else</span>
+436:         <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] <span class="ruby-operator">?</span> <span class="ruby-keyword kw">true</span> <span class="ruby-operator">:</span> <span class="ruby-keyword kw">false</span>
+437:       <span class="ruby-keyword kw">end</span>
+438:     <span class="ruby-keyword kw">else</span>
+439:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'forcearray'</span>] = <span class="ruby-constant">DEF_FORCE_ARRAY</span>
+440:     <span class="ruby-keyword kw">end</span>
+441: 
+442:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'grouptags'</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@options</span>[<span class="ruby-value str">'grouptags'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+443:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Illegal value for 'GroupTags' option - expected a Hash.&quot;</span>
+444:     <span class="ruby-keyword kw">end</span>
+445: 
+446:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'variables'</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@options</span>[<span class="ruby-value str">'variables'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+447:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Illegal value for 'Variables' option - expected a Hash.&quot;</span>
+448:     <span class="ruby-keyword kw">end</span>
+449: 
+450:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'variables'</span>)
+451:       <span class="ruby-ivar">@_var_values</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'variables'</span>]
+452:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'varattr'</span>)
+453:       <span class="ruby-ivar">@_var_values</span> = {}
+454:     <span class="ruby-keyword kw">end</span>
+455:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="has-mixed-content--method" class="method-detail ">
+				<a name="method-i-has_mixed_content%3F"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">has_mixed_content?</span><span
+						class="method-args">(element)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Determines, if a document element has mixed content.
+</p>
+<table>
+<tr><td valign="top">element</td><td><p>
+Document element to be checked.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="has-mixed-content--source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 720</span>
+720:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">has_mixed_content?</span>(<span class="ruby-identifier">element</span>)
+721:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">element</span>.<span class="ruby-identifier">has_text?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">element</span>.<span class="ruby-identifier">has_elements?</span>
+722:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">element</span>.<span class="ruby-identifier">texts</span>.<span class="ruby-identifier">join</span>(<span class="ruby-value str">''</span>) <span class="ruby-operator">!~</span> <span class="ruby-regexp re">/^\s*$/</span>
+723:     <span class="ruby-keyword kw">end</span>
+724:     <span class="ruby-keyword kw">false</span>
+725:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="hash-to-array-method" class="method-detail ">
+				<a name="method-i-hash_to_array"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">hash_to_array</span><span
+						class="method-args">(parent, hashref)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Attempts to unfold a hash of hashes into an array of hashes. Returns a
+reference to th array on success or the original hash, if unfolding is not
+possible.
+</p>
+<table>
+<tr><td valign="top">parent</td><td></td></tr>
+<tr><td valign="top">hashref</td><td><p>
+Reference to the hash to be unfolded.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="hash-to-array-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 881</span>
+881:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">hash_to_array</span>(<span class="ruby-identifier">parent</span>, <span class="ruby-identifier">hashref</span>)
+882:     <span class="ruby-identifier">arrayref</span> = []
+883:     <span class="ruby-identifier">hashref</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+884:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">hashref</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+885: 
+886:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+887:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">hashref</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">parent</span>)
+888:         <span class="ruby-identifier">arrayref</span> <span class="ruby-operator">&lt;&lt;</span> { <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>][<span class="ruby-identifier">parent</span>][<span class="ruby-value">0</span>] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">key</span> }.<span class="ruby-identifier">update</span>(<span class="ruby-identifier">value</span>)
+889:       <span class="ruby-keyword kw">else</span>
+890:         <span class="ruby-identifier">arrayref</span> <span class="ruby-operator">&lt;&lt;</span> { <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>][<span class="ruby-value">0</span>] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">key</span> }.<span class="ruby-identifier">update</span>(<span class="ruby-identifier">value</span>)
+891:       <span class="ruby-keyword kw">end</span>
+892:     }
+893:     <span class="ruby-identifier">arrayref</span>
+894:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="load-xml-file-method" class="method-detail ">
+				<a name="method-i-load_xml_file"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">load_xml_file</span><span
+						class="method-args">(filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Loads and parses an XML configuration file.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Name of the configuration file to be loaded.
+</p>
+</td></tr>
+</table>
+<p>
+The following exceptions may be raised:
+</p>
+<table>
+<tr><td valign="top">Errno::ENOENT</td><td><p>
+If the specified file does not exist.
+</p>
+</td></tr>
+<tr><td valign="top">REXML::ParseException</td><td><p>
+If the specified file is not wellformed.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="load-xml-file-source">
+<pre>
+      <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 1000</span>
+1000:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">load_xml_file</span>(<span class="ruby-identifier">filename</span>)
+1001:     <span class="ruby-identifier">parse</span>(<span class="ruby-constant">IO</span><span class="ruby-operator">::</span><span class="ruby-identifier">read</span>(<span class="ruby-identifier">filename</span>))
+1002:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="merge-method" class="method-detail ">
+				<a name="method-i-merge"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">merge</span><span
+						class="method-args">(hash, key, value)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Adds a new key/value pair to an existing Hash. If the key to be added does
+already exist and the existing value associated with key is not an Array,
+it will be converted into an Array. Then the new value is appended to that
+Array.
+</p>
+<table>
+<tr><td valign="top">hash</td><td><p>
+Hash to add key/value pair to.
+</p>
+</td></tr>
+<tr><td valign="top">key</td><td><p>
+Key to be added.
+</p>
+</td></tr>
+<tr><td valign="top">value</td><td><p>
+Value to be associated with key.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="merge-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 644</span>
+644:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">merge</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span>)
+645:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">String</span>)
+646:       <span class="ruby-identifier">value</span> = <span class="ruby-identifier">normalise_space</span>(<span class="ruby-identifier">value</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'normalisespace'</span>] <span class="ruby-operator">==</span> <span class="ruby-value">2</span>
+647: 
+648:       <span class="ruby-comment cmt"># do variable substitutions</span>
+649:       <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@_var_values</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">||</span> <span class="ruby-ivar">@_var_values</span>.<span class="ruby-identifier">empty?</span>
+650:         <span class="ruby-identifier">value</span>.<span class="ruby-identifier">gsub!</span>(<span class="ruby-regexp re">/\$\{(\w+)\}/</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">x</span><span class="ruby-operator">|</span> <span class="ruby-identifier">get_var</span>(<span class="ruby-node">$1</span>) }
+651:       <span class="ruby-keyword kw">end</span>
+652:       
+653:       <span class="ruby-comment cmt"># look for variable definitions</span>
+654:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'varattr'</span>)
+655:         <span class="ruby-identifier">varattr</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'varattr'</span>]
+656:         <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">varattr</span>)
+657:           <span class="ruby-identifier">set_var</span>(<span class="ruby-identifier">hash</span>[<span class="ruby-identifier">varattr</span>], <span class="ruby-identifier">value</span>)
+658:         <span class="ruby-keyword kw">end</span>
+659:       <span class="ruby-keyword kw">end</span>
+660:     <span class="ruby-keyword kw">end</span>
+661:     
+662:     <span class="ruby-comment cmt">#patch for converting keys to symbols</span>
+663:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'keytosymbol'</span>)
+664:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keytosymbol'</span>] <span class="ruby-operator">==</span> <span class="ruby-keyword kw">true</span>
+665:         <span class="ruby-identifier">key</span> = <span class="ruby-identifier">key</span>.<span class="ruby-identifier">to_s</span>.<span class="ruby-identifier">downcase</span>.<span class="ruby-identifier">to_sym</span>
+666:       <span class="ruby-keyword kw">end</span>
+667:     <span class="ruby-keyword kw">end</span>
+668:     
+669:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">key</span>)
+670:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>].<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+671:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">value</span>
+672:       <span class="ruby-keyword kw">else</span>
+673:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = [ <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>], <span class="ruby-identifier">value</span> ]
+674:       <span class="ruby-keyword kw">end</span>
+675:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>) <span class="ruby-comment cmt"># Handle anonymous arrays.</span>
+676:       <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = [ <span class="ruby-identifier">value</span> ]
+677:     <span class="ruby-keyword kw">else</span>
+678:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">force_array?</span>(<span class="ruby-identifier">key</span>)
+679:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = [ <span class="ruby-identifier">value</span> ]
+680:       <span class="ruby-keyword kw">else</span>
+681:         <span class="ruby-identifier">hash</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span>
+682:       <span class="ruby-keyword kw">end</span>
+683:     <span class="ruby-keyword kw">end</span>
+684:     <span class="ruby-identifier">hash</span>
+685:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="node-to-text-method" class="method-detail ">
+				<a name="method-i-node_to_text"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">node_to_text</span><span
+						class="method-args">(node, default = nil)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Converts a document node into a String. If the node could not be converted
+into a String for any reason, default will be returned.
+</p>
+<table>
+<tr><td valign="top">node</td><td><p>
+Document node to be converted.
+</p>
+</td></tr>
+<tr><td valign="top">default</td><td><p>
+Value to be returned, if node could not be converted.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="node-to-text-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 937</span>
+937:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">node_to_text</span>(<span class="ruby-identifier">node</span>, <span class="ruby-identifier">default</span> = <span class="ruby-keyword kw">nil</span>)
+938:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">node</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">REXML</span><span class="ruby-operator">::</span><span class="ruby-constant">Element</span>) 
+939:       <span class="ruby-identifier">node</span>.<span class="ruby-identifier">texts</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">t</span><span class="ruby-operator">|</span> <span class="ruby-identifier">t</span>.<span class="ruby-identifier">value</span> }.<span class="ruby-identifier">join</span>(<span class="ruby-value str">''</span>)
+940:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">node</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">REXML</span><span class="ruby-operator">::</span><span class="ruby-constant">Attribute</span>)
+941:       <span class="ruby-identifier">node</span>.<span class="ruby-identifier">value</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">?</span> <span class="ruby-identifier">default</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">node</span>.<span class="ruby-identifier">value</span>.<span class="ruby-identifier">strip</span>
+942:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">node</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">REXML</span><span class="ruby-operator">::</span><span class="ruby-constant">Text</span>)
+943:       <span class="ruby-identifier">node</span>.<span class="ruby-identifier">value</span>.<span class="ruby-identifier">strip</span>
+944:     <span class="ruby-keyword kw">else</span>
+945:       <span class="ruby-identifier">default</span>
+946:     <span class="ruby-keyword kw">end</span>
+947:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="normalise-space-method" class="method-detail ">
+				<a name="method-i-normalise_space"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">normalise_space</span><span
+						class="method-args">(text)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Removes leading and trailing whitespace and sequences of whitespaces from a
+string.
+</p>
+<table>
+<tr><td valign="top">text</td><td><p>
+String to be normalised.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="normalise-space-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 909</span>
+909:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">normalise_space</span>(<span class="ruby-identifier">text</span>)
+910:     <span class="ruby-identifier">text</span>.<span class="ruby-identifier">strip</span>.<span class="ruby-identifier">gsub</span>(<span class="ruby-regexp re">/\s\s+/</span>, <span class="ruby-value str">' '</span>)
+911:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="normalize-option-names-method" class="method-detail ">
+				<a name="method-i-normalize_option_names"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">normalize_option_names</span><span
+						class="method-args">(options, known_options)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Normalizes option names in a hash, i.e., turns all characters to lower case
+and removes all underscores. Additionally, this method checks, if an
+unknown option was used and raises an according exception.
+</p>
+<table>
+<tr><td valign="top">options</td><td><p>
+Hash to be normalized.
+</p>
+</td></tr>
+<tr><td valign="top">known_options</td><td><p>
+List of known options.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="normalize-option-names-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 298</span>
+298:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">normalize_option_names</span>(<span class="ruby-identifier">options</span>, <span class="ruby-identifier">known_options</span>)
+299:     <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">options</span>.<span class="ruby-identifier">nil?</span>
+300:     <span class="ruby-identifier">result</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span>
+301:     <span class="ruby-identifier">options</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+302:       <span class="ruby-identifier">lkey</span> = <span class="ruby-identifier">key</span>.<span class="ruby-identifier">downcase</span>
+303:       <span class="ruby-identifier">lkey</span>.<span class="ruby-identifier">gsub!</span>(<span class="ruby-regexp re">/_/</span>, <span class="ruby-value str">''</span>)
+304:       <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">known_options</span>.<span class="ruby-identifier">member?</span>(<span class="ruby-identifier">lkey</span>)
+305:         <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Unrecognised option: #{lkey}.&quot;</span>
+306:       <span class="ruby-keyword kw">end</span>
+307:       <span class="ruby-identifier">result</span>[<span class="ruby-identifier">lkey</span>] = <span class="ruby-identifier">value</span>
+308:     }
+309:     <span class="ruby-identifier">result</span>
+310:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="parse-method" class="method-detail ">
+				<a name="method-i-parse"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">parse</span><span
+						class="method-args">(xml_string)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Parses an XML string and returns the according document.
+</p>
+<table>
+<tr><td valign="top">xml_string</td><td><p>
+XML string to be parsed.
+</p>
+</td></tr>
+</table>
+<p>
+The following exception may be raised:
+</p>
+<table>
+<tr><td valign="top">REXML::ParseException</td><td><p>
+If the specified file is not wellformed.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="parse-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 958</span>
+958:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">xml_string</span>)
+959:     <span class="ruby-constant">Document</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">xml_string</span>)
+960:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="put-into-cache-method" class="method-detail ">
+				<a name="method-i-put_into_cache"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">put_into_cache</span><span
+						class="method-args">(data, filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Caches the data belonging to a certain file.
+</p>
+<table>
+<tr><td valign="top">data</td><td><p>
+Data to be cached.
+</p>
+</td></tr>
+<tr><td valign="top">filename</td><td><p>
+Name of file the data was read from.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="put-into-cache-source">
+<pre>
+      <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 1010</span>
+1010:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">put_into_cache</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+1011:     <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'cache'</span>)
+1012:       <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'cache'</span>].<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">scheme</span><span class="ruby-operator">|</span>
+1013:         <span class="ruby-keyword kw">case</span>(<span class="ruby-identifier">scheme</span>)
+1014:         <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'storable'</span>
+1015:           <span class="ruby-identifier">@@cache</span>.<span class="ruby-identifier">save_storable</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+1016:         <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'mem_share'</span>
+1017:           <span class="ruby-identifier">@@cache</span>.<span class="ruby-identifier">save_mem_share</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+1018:         <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'mem_copy'</span>
+1019:           <span class="ruby-identifier">@@cache</span>.<span class="ruby-identifier">save_mem_copy</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+1020:         <span class="ruby-keyword kw">else</span>
+1021:           <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Unsupported caching scheme: &lt;#{scheme}&gt;.&quot;</span>
+1022:         <span class="ruby-keyword kw">end</span>
+1023:       }
+1024:     <span class="ruby-keyword kw">end</span>
+1025:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="scalar-method" class="method-detail ">
+				<a name="method-i-scalar"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">scalar</span><span
+						class="method-args">(value)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Checks, if a certain value is a &#8220;scalar&#8221; value. Whatever that
+will be in Ruby &#8230; ;-)
+</p>
+<table>
+<tr><td valign="top">value</td><td><p>
+Value to be checked.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="scalar-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 868</span>
+868:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">value</span>)
+869:     <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">false</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+870:     <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span>
+871:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="set-var-method" class="method-detail ">
+				<a name="method-i-set_var"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">set_var</span><span
+						class="method-args">(name, value)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Called when a variable definition is encountered in the XML. A variable
+definition looks like
+</p>
+<pre>
+   &lt;element attrname=&quot;name&quot;&gt;value&lt;/element&gt;
+</pre>
+<p>
+where attrname matches the varattr setting.
+</p>
+					
+
+					
+					<div class="method-source-code"
+						id="set-var-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 731</span>
+731:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">set_var</span>(<span class="ruby-identifier">name</span>, <span class="ruby-identifier">value</span>)
+732:     <span class="ruby-ivar">@_var_values</span>[<span class="ruby-identifier">name</span>] = <span class="ruby-identifier">value</span>
+733:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="value-to-xml-method" class="method-detail ">
+				<a name="method-i-value_to_xml"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">value_to_xml</span><span
+						class="method-args">(ref, name, indent)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Recurses through a data structure building up and returning an XML
+representation of that structure as a string.
+</p>
+<table>
+<tr><td valign="top">ref</td><td><p>
+Reference to the data structure to be encoded.
+</p>
+</td></tr>
+<tr><td valign="top">name</td><td><p>
+The XML tag name to be used for this item.
+</p>
+</td></tr>
+<tr><td valign="top">indent</td><td><p>
+A string of spaces for use as the current indent level.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="value-to-xml-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 754</span>
+754:   <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">value_to_xml</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">indent</span>)
+755:     <span class="ruby-identifier">named</span> = <span class="ruby-operator">!</span><span class="ruby-identifier">name</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">!=</span> <span class="ruby-value str">''</span>
+756:     <span class="ruby-identifier">nl</span>    = <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'noindent'</span>) <span class="ruby-operator">?</span> <span class="ruby-value str">''</span> <span class="ruby-operator">:</span> <span class="ruby-value str">&quot;\n&quot;</span>
+757: 
+758:     <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">ref</span>)
+759:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@ancestors</span>.<span class="ruby-identifier">member?</span>(<span class="ruby-identifier">ref</span>)
+760:         <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Circular data structures not supported!&quot;</span>
+761:       <span class="ruby-keyword kw">end</span>
+762:       <span class="ruby-ivar">@ancestors</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">ref</span>
+763:     <span class="ruby-keyword kw">else</span>
+764:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">named</span>
+765:         <span class="ruby-keyword kw">return</span> [<span class="ruby-identifier">indent</span>, <span class="ruby-value str">'&lt;'</span>, <span class="ruby-identifier">name</span>, <span class="ruby-value str">'&gt;'</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noescape'</span>] <span class="ruby-operator">?</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">to_s</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">escape_value</span>(<span class="ruby-identifier">ref</span>.<span class="ruby-identifier">to_s</span>), <span class="ruby-value str">'&lt;/'</span>, <span class="ruby-identifier">name</span>, <span class="ruby-value str">'&gt;'</span>, <span class="ruby-identifier">nl</span>].<span class="ruby-identifier">join</span>(<span class="ruby-value str">''</span>)
+766:       <span class="ruby-keyword kw">else</span>
+767:         <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">to_s</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">nl</span>
+768:       <span class="ruby-keyword kw">end</span>
+769:     <span class="ruby-keyword kw">end</span>
+770: 
+771:     <span class="ruby-comment cmt"># Unfold hash to array if possible.</span>
+772:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-identifier">ref</span>.<span class="ruby-identifier">empty?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keyattr'</span>].<span class="ruby-identifier">empty?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">indent</span> <span class="ruby-operator">!=</span> <span class="ruby-value str">''</span>
+773:       <span class="ruby-identifier">ref</span> = <span class="ruby-identifier">hash_to_array</span>(<span class="ruby-identifier">name</span>, <span class="ruby-identifier">ref</span>)
+774:     <span class="ruby-keyword kw">end</span>
+775: 
+776:     <span class="ruby-identifier">result</span> = []
+777:     <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+778:       <span class="ruby-comment cmt"># Reintermediate grouped values if applicable.</span>
+779:       <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'grouptags'</span>)
+780:         <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+781:           <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'grouptags'</span>].<span class="ruby-identifier">has_key?</span>(<span class="ruby-identifier">key</span>)
+782:             <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">key</span>] = { <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'grouptags'</span>][<span class="ruby-identifier">key</span>] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">value</span> }
+783:           <span class="ruby-keyword kw">end</span>
+784:         }
+785:       <span class="ruby-keyword kw">end</span>
+786:       
+787:       <span class="ruby-identifier">nested</span> = []
+788:       <span class="ruby-identifier">text_content</span> = <span class="ruby-keyword kw">nil</span>
+789:       <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">named</span>
+790:         <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">indent</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&lt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">name</span>
+791:       <span class="ruby-keyword kw">end</span>
+792: 
+793:       <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">ref</span>.<span class="ruby-identifier">empty?</span>
+794:         <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+795:           <span class="ruby-keyword kw">next</span> <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">key</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">key</span>.<span class="ruby-identifier">to_s</span>[<span class="ruby-value">0</span>, <span class="ruby-value">1</span>] <span class="ruby-operator">==</span> <span class="ruby-value str">'-'</span>
+796:           <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">nil?</span>
+797:             <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'suppressempty'</span>) <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'suppressempty'</span>].<span class="ruby-identifier">nil?</span>
+798:               <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Use of uninitialized value!&quot;</span>
+799:             <span class="ruby-keyword kw">end</span>
+800:             <span class="ruby-identifier">value</span> = {}
+801:           <span class="ruby-keyword kw">end</span>
+802: 
+803:           <span class="ruby-comment cmt"># Check for the '@' attribute prefix to allow separation of attributes and elements</span>
+804:           <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noattr'</span>] <span class="ruby-operator">||</span>
+805:              (<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'attrprefix'</span>] <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span>(<span class="ruby-identifier">key</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/^@(.*)/</span>)) <span class="ruby-operator">||</span>
+806:              <span class="ruby-operator">!</span><span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">value</span>)
+807:             <span class="ruby-identifier">nested</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">value_to_xml</span>(<span class="ruby-identifier">value</span>, <span class="ruby-identifier">key</span>, <span class="ruby-identifier">indent</span> <span class="ruby-operator">+</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'indent'</span>])
+808:           <span class="ruby-keyword kw">else</span>
+809:             <span class="ruby-identifier">value</span> = <span class="ruby-identifier">value</span>.<span class="ruby-identifier">to_s</span>
+810:             <span class="ruby-identifier">value</span> = <span class="ruby-identifier">escape_value</span>(<span class="ruby-identifier">value</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noescape'</span>]
+811:             <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">key</span> <span class="ruby-operator">==</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'contentkey'</span>]
+812:               <span class="ruby-identifier">text_content</span> = <span class="ruby-identifier">value</span>
+813:             <span class="ruby-keyword kw">else</span>
+814:               <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">' '</span> <span class="ruby-operator">&lt;&lt;</span> (<span class="ruby-node">$1</span><span class="ruby-operator">||</span><span class="ruby-identifier">key</span>) <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'=&quot;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">value</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&quot;'</span>
+815:             <span class="ruby-keyword kw">end</span>
+816:           <span class="ruby-keyword kw">end</span>
+817:         }
+818:       <span class="ruby-keyword kw">else</span>
+819:         <span class="ruby-identifier">text_content</span> = <span class="ruby-value str">''</span>
+820:       <span class="ruby-keyword kw">end</span>
+821: 
+822:       <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">nested</span>.<span class="ruby-identifier">empty?</span> <span class="ruby-operator">||</span> <span class="ruby-operator">!</span><span class="ruby-identifier">text_content</span>.<span class="ruby-identifier">nil?</span>
+823:         <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">named</span>
+824:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&gt;'</span>
+825:           <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">text_content</span>.<span class="ruby-identifier">nil?</span>
+826:             <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">text_content</span>
+827:             <span class="ruby-identifier">nested</span>[<span class="ruby-value">0</span>].<span class="ruby-identifier">sub!</span>(<span class="ruby-regexp re">/^\s+/</span>, <span class="ruby-value str">''</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">nested</span>.<span class="ruby-identifier">empty?</span>
+828:           <span class="ruby-keyword kw">else</span>
+829:             <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nl</span>
+830:           <span class="ruby-keyword kw">end</span>
+831:           <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">nested</span>.<span class="ruby-identifier">empty?</span>
+832:             <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nested</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">indent</span>
+833:           <span class="ruby-keyword kw">end</span>
+834:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&lt;/'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&gt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nl</span>
+835:         <span class="ruby-keyword kw">else</span>
+836:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nested</span>
+837:         <span class="ruby-keyword kw">end</span>
+838:       <span class="ruby-keyword kw">else</span>
+839:         <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">' /&gt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nl</span>
+840:       <span class="ruby-keyword kw">end</span>
+841:     <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+842:       <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+843:         <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">value</span>)
+844:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">indent</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&lt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&gt;'</span>
+845:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> (<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'noescape'</span>] <span class="ruby-operator">?</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">to_s</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">escape_value</span>(<span class="ruby-identifier">value</span>.<span class="ruby-identifier">to_s</span>))
+846:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&lt;/'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&gt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nl</span>
+847:         <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">value</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+848:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">value_to_xml</span>(<span class="ruby-identifier">value</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">indent</span>)
+849:         <span class="ruby-keyword kw">else</span>
+850:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">indent</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&lt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&gt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nl</span>
+851:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">value_to_xml</span>(<span class="ruby-identifier">value</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'anonymoustag'</span>], <span class="ruby-identifier">indent</span> <span class="ruby-operator">+</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'indent'</span>])
+852:           <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">indent</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&lt;/'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'&gt;'</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">nl</span>
+853:         <span class="ruby-keyword kw">end</span>
+854:       }
+855:     <span class="ruby-keyword kw">else</span>
+856:       <span class="ruby-comment cmt"># Probably, this is obsolete.</span>
+857:       <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Can't encode a value of type: #{ref.type}.&quot;</span>
+858:     <span class="ruby-keyword kw">end</span>
+859:     <span class="ruby-ivar">@ancestors</span>.<span class="ruby-identifier">pop</span> <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">ref</span>)
+860:     <span class="ruby-identifier">result</span>.<span class="ruby-identifier">join</span>(<span class="ruby-value str">''</span>)
+861:   <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+		</div>
+	
+
+	</div>
+
+
+	<div id="rdoc-debugging-section-dump" class="debugging-section">
+	
+		<p>Disabled; run with --debug to generate this.</p>
+	
+	</div>
+
+	<div id="validator-badges">
+		<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+		<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
+			Rdoc Generator</a> 1.1.6</small>.</p>
+	</div>
+
+</body>
+</html>
+
diff --git a/docs/api/XmlSimple/Cache.html b/docs/api/XmlSimple/Cache.html
new file mode 100644
index 0000000..1dd96b0
--- /dev/null
+++ b/docs/api/XmlSimple/Cache.html
@@ -0,0 +1,590 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+
+	<title>Class: XmlSimple::Cache</title>
+
+	<link rel="stylesheet" href="../rdoc.css" type="text/css" media="screen" />
+
+	<script src="../js/jquery.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="../js/thickbox-compressed.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="../js/quicksearch.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="../js/darkfish.js" type="text/javascript"
+		charset="utf-8"></script>
+
+</head>
+<body class="class">
+
+	<div id="metadata">
+		<div id="home-metadata">
+			<div id="home-section" class="section">
+        <h3 class="section-header">
+          <a href="../index.html">Home</a>
+          <a href="../index.html#classes">Classes</a>
+          <a href="../index.html#methods">Methods</a>
+        </h3>
+			</div>
+		</div>
+
+		<div id="file-metadata">
+			<div id="file-list-section" class="section">
+				<h3 class="section-header">In Files</h3>
+				<div class="section-body">
+					<ul>
+					
+						<li><a href="../lib/xmlsimple_rb.html?TB_iframe=true&amp;height=550&amp;width=785"
+							class="thickbox" title="lib/xmlsimple.rb">lib/xmlsimple.rb</a></li>
+					
+					</ul>
+				</div>
+			</div>
+
+			
+		</div>
+
+		<div id="class-metadata">
+
+			<!-- Parent Class -->
+			
+			<div id="parent-class-section" class="section">
+				<h3 class="section-header">Parent</h3>
+				
+				<p class="link">Object</p>
+				
+			</div>
+			
+
+			<!-- Namespace Contents -->
+			
+
+			<!-- Method Quickref -->
+			
+			<div id="method-list-section" class="section">
+				<h3 class="section-header">Methods</h3>
+				<ul class="link-list">
+					
+					<li><a href="#method-c-new">::new</a></li>
+					
+					<li><a href="#method-i-get_cache_filename">#get_cache_filename</a></li>
+					
+					<li><a href="#method-i-get_from_memory_cache">#get_from_memory_cache</a></li>
+					
+					<li><a href="#method-i-restore_mem_copy">#restore_mem_copy</a></li>
+					
+					<li><a href="#method-i-restore_mem_share">#restore_mem_share</a></li>
+					
+					<li><a href="#method-i-restore_storable">#restore_storable</a></li>
+					
+					<li><a href="#method-i-save_mem_copy">#save_mem_copy</a></li>
+					
+					<li><a href="#method-i-save_mem_share">#save_mem_share</a></li>
+					
+					<li><a href="#method-i-save_storable">#save_storable</a></li>
+					
+				</ul>
+			</div>
+			
+
+			<!-- Included Modules -->
+			
+		</div>
+
+		<div id="project-metadata">
+			
+			
+
+			<div id="classindex-section" class="section project-section">
+				<h3 class="section-header">Class Index
+					<span class="search-toggle"><img src="../images/find.png"
+						height="16" width="16" alt="[+]"
+						title="show/hide quicksearch" /></span></h3>
+				<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
+				<fieldset>
+					<legend>Quicksearch</legend>
+					<input type="text" name="quicksearch" value=""
+						class="quicksearch-field" />
+				</fieldset>
+				</form>
+
+				<ul class="link-list">
+				
+					<li><a href="../XmlSimple.html">XmlSimple</a></li>
+				
+					<li><a href="../XmlSimple/Cache.html">XmlSimple::Cache</a></li>
+				
+				</ul>
+				<div id="no-class-search-results" style="display: none;">No matching classes.</div>
+			</div>
+
+			
+		</div>
+	</div>
+
+	<div id="documentation">
+		<h1 class="class">XmlSimple::Cache</h1>
+
+		<div id="description">
+			<p>
+A simple cache for XML documents that were already transformed by xml_in.
+</p>
+
+		</div>
+
+		<!-- Constants -->
+		
+
+		<!-- Attributes -->
+		
+
+		<!-- Methods -->
+		
+		<div id="public-class-method-details" class="method-section section">
+			<h3 class="section-header">Public Class Methods</h3>
+
+		
+			<div id="new-method" class="method-detail ">
+				<a name="method-c-new"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">new</span><span
+						class="method-args">()</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Creates and initializes a new <a href="Cache.html">Cache</a> object.
+</p>
+					
+
+					
+					<div class="method-source-code"
+						id="new-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 20</span>
+20:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>
+21:       <span class="ruby-ivar">@mem_share_cache</span> = {}
+22:       <span class="ruby-ivar">@mem_copy_cache</span>  = {}
+23:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+		</div>
+	
+		<div id="public-instance-method-details" class="method-section section">
+			<h3 class="section-header">Public Instance Methods</h3>
+
+		
+			<div id="restore-mem-copy-method" class="method-detail ">
+				<a name="method-i-restore_mem_copy"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">restore_mem_copy</span><span
+						class="method-args">(filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Restores a data structure from a memory cache. If restoring the data
+structure failed for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Name of the file belonging to the data structure.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="restore-mem-copy-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 87</span>
+87:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">restore_mem_copy</span>(<span class="ruby-identifier">filename</span>)
+88:       <span class="ruby-identifier">data</span> = <span class="ruby-identifier">get_from_memory_cache</span>(<span class="ruby-identifier">filename</span>, <span class="ruby-ivar">@mem_share_cache</span>)
+89:       <span class="ruby-identifier">data</span> = <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">load</span>(<span class="ruby-identifier">data</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">data</span>.<span class="ruby-identifier">nil?</span>
+90:       <span class="ruby-identifier">data</span>
+91:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="restore-mem-share-method" class="method-detail ">
+				<a name="method-i-restore_mem_share"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">restore_mem_share</span><span
+						class="method-args">(filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Restores a data structure from a shared memory cache. You should consider
+these elements as &#8220;read only&#8221;. If restoring the data structure
+failed for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Name of the file belonging to the data structure.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="restore-mem-share-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 67</span>
+67:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">restore_mem_share</span>(<span class="ruby-identifier">filename</span>)
+68:       <span class="ruby-identifier">get_from_memory_cache</span>(<span class="ruby-identifier">filename</span>, <span class="ruby-ivar">@mem_share_cache</span>)
+69:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="restore-storable-method" class="method-detail ">
+				<a name="method-i-restore_storable"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">restore_storable</span><span
+						class="method-args">(filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Restores a data structure from a file. If restoring the data structure
+failed for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Name of the file belonging to the data structure.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="restore-storable-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 41</span>
+41:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">restore_storable</span>(<span class="ruby-identifier">filename</span>)
+42:       <span class="ruby-identifier">cache_file</span> = <span class="ruby-identifier">get_cache_filename</span>(<span class="ruby-identifier">filename</span>)
+43:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">exist?</span>(<span class="ruby-identifier">cache_file</span>)
+44:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">mtime</span>(<span class="ruby-identifier">cache_file</span>).<span class="ruby-identifier">to_i</span> <span class="ruby-operator">&gt;</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">mtime</span>(<span class="ruby-identifier">filename</span>).<span class="ruby-identifier">to_i</span>
+45:       <span class="ruby-identifier">data</span> = <span class="ruby-keyword kw">nil</span>
+46:       <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-identifier">cache_file</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">f</span><span class="ruby-operator">|</span> <span class="ruby-identifier">data</span> = <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">load</span>(<span class="ruby-identifier">f</span>) }
+47:       <span class="ruby-identifier">data</span>
+48:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="save-mem-copy-method" class="method-detail ">
+				<a name="method-i-save_mem_copy"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">save_mem_copy</span><span
+						class="method-args">(data, filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Copies a data structure to a memory cache.
+</p>
+<table>
+<tr><td valign="top">data</td><td><p>
+Data structure to be copied.
+</p>
+</td></tr>
+<tr><td valign="top">filename</td><td><p>
+Name of the file belonging to the data structure.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="save-mem-copy-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 77</span>
+77:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_mem_copy</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+78:       <span class="ruby-ivar">@mem_share_cache</span>[<span class="ruby-identifier">filename</span>] = [<span class="ruby-constant">Time</span><span class="ruby-operator">::</span><span class="ruby-identifier">now</span>.<span class="ruby-identifier">to_i</span>, <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">dump</span>(<span class="ruby-identifier">data</span>)]
+79:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="save-mem-share-method" class="method-detail ">
+				<a name="method-i-save_mem_share"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">save_mem_share</span><span
+						class="method-args">(data, filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Saves a data structure in a shared memory cache.
+</p>
+<table>
+<tr><td valign="top">data</td><td><p>
+Data structure to be saved.
+</p>
+</td></tr>
+<tr><td valign="top">filename</td><td><p>
+Name of the file belonging to the data structure.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="save-mem-share-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 56</span>
+56:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_mem_share</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+57:       <span class="ruby-ivar">@mem_share_cache</span>[<span class="ruby-identifier">filename</span>] = [<span class="ruby-constant">Time</span><span class="ruby-operator">::</span><span class="ruby-identifier">now</span>.<span class="ruby-identifier">to_i</span>, <span class="ruby-identifier">data</span>]
+58:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="save-storable-method" class="method-detail ">
+				<a name="method-i-save_storable"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">save_storable</span><span
+						class="method-args">(data, filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Saves a data structure into a file.
+</p>
+<table>
+<tr><td valign="top">data</td><td><p>
+Data structure to be saved.
+</p>
+</td></tr>
+<tr><td valign="top">filename</td><td><p>
+Name of the file belonging to the data structure.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="save-storable-source">
+<pre>
+    <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 31</span>
+31:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_storable</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+32:       <span class="ruby-identifier">cache_file</span> = <span class="ruby-identifier">get_cache_filename</span>(<span class="ruby-identifier">filename</span>)
+33:       <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-identifier">cache_file</span>, <span class="ruby-value str">&quot;w+&quot;</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">f</span><span class="ruby-operator">|</span> <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">dump</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">f</span>) }
+34:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+		</div>
+	
+		<div id="private-instance-method-details" class="method-section section">
+			<h3 class="section-header">Private Instance Methods</h3>
+
+		
+			<div id="get-cache-filename-method" class="method-detail ">
+				<a name="method-i-get_cache_filename"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">get_cache_filename</span><span
+						class="method-args">(filename)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Returns the &#8220;cache filename&#8221; belonging to a filename, i.e. the
+extension &#8217;.xml&#8217; in the original filename will be replaced by
+&#8217;.stor&#8217;. If filename does not have this extension,
+&#8217;.stor&#8217; will be appended.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Filename to get &#8220;cache filename&#8221; for.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="get-cache-filename-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 102</span>
+102:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">get_cache_filename</span>(<span class="ruby-identifier">filename</span>)
+103:       <span class="ruby-identifier">filename</span>.<span class="ruby-identifier">sub</span>(<span class="ruby-regexp re">/(\.xml)?$/</span>, <span class="ruby-value str">'.stor'</span>)
+104:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+			<div id="get-from-memory-cache-method" class="method-detail ">
+				<a name="method-i-get_from_memory_cache"></a>
+
+				<div class="method-heading">
+				
+					<span class="method-name">get_from_memory_cache</span><span
+						class="method-args">(filename, cache)</span>
+					<span class="method-click-advice">click to toggle source</span>
+				
+				</div>
+
+				<div class="method-description">
+					
+					<p>
+Returns a cache entry from a memory cache belonging to a certain filename.
+If no entry could be found for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename</td><td><p>
+Name of the file the cache entry belongs to.
+</p>
+</td></tr>
+<tr><td valign="top">cache</td><td><p>
+Memory cache to get entry from.
+</p>
+</td></tr>
+</table>
+					
+
+					
+					<div class="method-source-code"
+						id="get-from-memory-cache-source">
+<pre>
+     <span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 114</span>
+114:     <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">get_from_memory_cache</span>(<span class="ruby-identifier">filename</span>, <span class="ruby-identifier">cache</span>)
+115:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">cache</span>[<span class="ruby-identifier">filename</span>]
+116:       <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">cache</span>[<span class="ruby-identifier">filename</span>][<span class="ruby-value">0</span>] <span class="ruby-operator">&gt;</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">mtime</span>(<span class="ruby-identifier">filename</span>).<span class="ruby-identifier">to_i</span>
+117:       <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">cache</span>[<span class="ruby-identifier">filename</span>][<span class="ruby-value">1</span>]
+118:     <span class="ruby-keyword kw">end</span></pre>
+					</div>
+					
+				</div>
+
+				
+
+				
+			</div>
+
+		
+		</div>
+	
+
+	</div>
+
+
+	<div id="rdoc-debugging-section-dump" class="debugging-section">
+	
+		<p>Disabled; run with --debug to generate this.</p>
+	
+	</div>
+
+	<div id="validator-badges">
+		<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+		<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
+			Rdoc Generator</a> 1.1.6</small>.</p>
+	</div>
+
+</body>
+</html>
+
diff --git a/docs/api/classes/XmlSimple.html b/docs/api/classes/XmlSimple.html
new file mode 100755
index 0000000..d0db012
--- /dev/null
+++ b/docs/api/classes/XmlSimple.html
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>Class: XmlSimple</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <meta http-equiv="Content-Script-Type" content="text/javascript" />
+  <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
+  <script type="text/javascript">
+  // <![CDATA[
+
+  function popupCode( url ) {
+    window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+  }
+
+  function toggleCode( id ) {
+    if ( document.getElementById )
+      elem = document.getElementById( id );
+    else if ( document.all )
+      elem = eval( "document.all." + id );
+    else
+      return false;
+
+    elemStyle = elem.style;
+    
+    if ( elemStyle.display != "block" ) {
+      elemStyle.display = "block"
+    } else {
+      elemStyle.display = "none"
+    }
+
+    return true;
+  }
+  
+  // Make codeblocks hidden by default
+  document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
+  
+  // ]]>
+  </script>
+
+</head>
+<body>
+
+
+
+    <div id="classHeader">
+        <table class="header-table">
+        <tr class="top-aligned-row">
+          <td><strong>Class</strong></td>
+          <td class="class-name-in-header">XmlSimple</td>
+        </tr>
+        <tr class="top-aligned-row">
+            <td><strong>In:</strong></td>
+            <td>
+                <a href="../files/lib/xmlsimple_rb.html">
+                lib/xmlsimple.rb
+                </a>
+        <br />
+            </td>
+        </tr>
+
+        <tr class="top-aligned-row">
+            <td><strong>Parent:</strong></td>
+            <td>
+                Object
+            </td>
+        </tr>
+        </table>
+    </div>
+  <!-- banner header -->
+
+  <div id="bodyContent">
+
+
+
+  <div id="contextContent">
+
+    <div id="description">
+      <p>
+Easy API to maintain XML (especially configuration files).
+</p>
+
+    </div>
+
+
+   </div>
+
+    <div id="method-list">
+      <h3 class="section-bar">Methods</h3>
+
+      <div class="name-list">
+      <a href="#M000001">new</a>&nbsp;&nbsp;
+      <a href="#M000002">xml_in</a>&nbsp;&nbsp;
+      <a href="#M000003">xml_in</a>&nbsp;&nbsp;
+      <a href="#M000004">xml_out</a>&nbsp;&nbsp;
+      <a href="#M000005">xml_out</a>&nbsp;&nbsp;
+      </div>
+    </div>
+
+  </div>
+
+
+    <!-- if includes -->
+    <div id="includes">
+      <h3 class="section-bar">Included Modules</h3>
+
+      <div id="includes-list">
+        <span class="include-name">REXML</span>
+      </div>
+    </div>
+
+    <div id="section">
+
+    <div id="class-list">
+      <h3 class="section-bar">Classes and Modules</h3>
+
+      Class <a href="XmlSimple/Cache.html" class="link">XmlSimple::Cache</a><br />
+
+    </div>
+
+    <div id="constants-list">
+      <h3 class="section-bar">Constants</h3>
+
+      <div class="name-list">
+        <table summary="Constants">
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">KNOWN_OPTIONS</td>
+          <td>=</td>
+          <td class="context-item-value">{     'in'  =&gt; %w(       keyattr keeproot forcecontent contentkey noattr       searchpath forcearray suppressempty anonymoustag       cache grouptags normalisespace normalizespace       variables varattr keytosymbol     ),     'out' =&gt; %w(       keyattr keeproot contentkey noattr rootname       xmldeclaration outputfile noescape suppressempty       anonymoustag indent grouptags noindent     )</td>
+          <td width="3em">&nbsp;</td>
+          <td class="context-item-desc">
+Declare options that are valid for <a
+href="XmlSimple.html#M000002">xml_in</a> and <a
+href="XmlSimple.html#M000004">xml_out</a>.
+
+</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_KEY_ATTRIBUTES</td>
+          <td>=</td>
+          <td class="context-item-value">[]</td>
+          <td width="3em">&nbsp;</td>
+          <td class="context-item-desc">
+Define some reasonable defaults.
+
+</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_ROOT_NAME</td>
+          <td>=</td>
+          <td class="context-item-value">'opt'</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_CONTENT_KEY</td>
+          <td>=</td>
+          <td class="context-item-value">'content'</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_XML_DECLARATION</td>
+          <td>=</td>
+          <td class="context-item-value">&quot;&lt;?xml version='1.0' standalone='yes'?&gt;&quot;</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_ANONYMOUS_TAG</td>
+          <td>=</td>
+          <td class="context-item-value">'anon'</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_FORCE_ARRAY</td>
+          <td>=</td>
+          <td class="context-item-value">true</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_INDENTATION</td>
+          <td>=</td>
+          <td class="context-item-value">'  '</td>
+        </tr>
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">DEF_KEY_TO_SYMBOL</td>
+          <td>=</td>
+          <td class="context-item-value">false</td>
+        </tr>
+        </table>
+      </div>
+    </div>
+
+
+
+      
+
+
+    <!-- if method_list -->
+    <div id="methods">
+      <h3 class="section-bar">Public Class methods</h3>
+
+      <div id="method-M000001" class="method-detail">
+        <a name="M000001"></a>
+
+        <div class="method-heading">
+          <a href="XmlSimple.src/M000001.html" target="Code" class="method-signature"
+            onclick="popupCode('XmlSimple.src/M000001.html');return false;">
+          <span class="method-name">new</span><span class="method-args">(defaults = nil)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Creates and intializes a <a href="XmlSimple.html#M000001">new</a> <a
+href="XmlSimple.html">XmlSimple</a> object.
+</p>
+<table>
+<tr><td valign="top">defaults:</td><td>Default values for options.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000003" class="method-detail">
+        <a name="M000003"></a>
+
+        <div class="method-heading">
+          <a href="XmlSimple.src/M000003.html" target="Code" class="method-signature"
+            onclick="popupCode('XmlSimple.src/M000003.html');return false;">
+          <span class="method-name">xml_in</span><span class="method-args">(string = nil, options = nil)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+This is the functional version of the instance method <a
+href="XmlSimple.html#M000002">xml_in</a>.
+</p>
+        </div>
+      </div>
+
+      <div id="method-M000005" class="method-detail">
+        <a name="M000005"></a>
+
+        <div class="method-heading">
+          <a href="XmlSimple.src/M000005.html" target="Code" class="method-signature"
+            onclick="popupCode('XmlSimple.src/M000005.html');return false;">
+          <span class="method-name">xml_out</span><span class="method-args">(hash, options = nil)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+This is the functional version of the instance method <a
+href="XmlSimple.html#M000004">xml_out</a>.
+</p>
+        </div>
+      </div>
+
+      <h3 class="section-bar">Public Instance methods</h3>
+
+      <div id="method-M000002" class="method-detail">
+        <a name="M000002"></a>
+
+        <div class="method-heading">
+          <a href="XmlSimple.src/M000002.html" target="Code" class="method-signature"
+            onclick="popupCode('XmlSimple.src/M000002.html');return false;">
+          <span class="method-name">xml_in</span><span class="method-args">(string = nil, options = nil)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Converts an XML document in the same way as the Perl module XML::Simple.
+</p>
+<table>
+<tr><td valign="top">string:</td><td>XML source. Could be one of the following:
+
+<ul>
+<li>nil: Tries to load and parse &#8217;&lt;scriptname&gt;.xml&#8217;.
+
+</li>
+<li>filename: Tries to load and parse filename.
+
+</li>
+<li>IO object: Reads from object until EOF is detected and parses result.
+
+</li>
+<li>XML string: Parses string.
+
+</li>
+</ul>
+</td></tr>
+<tr><td valign="top">options:</td><td>Options to be used.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000004" class="method-detail">
+        <a name="M000004"></a>
+
+        <div class="method-heading">
+          <a href="XmlSimple.src/M000004.html" target="Code" class="method-signature"
+            onclick="popupCode('XmlSimple.src/M000004.html');return false;">
+          <span class="method-name">xml_out</span><span class="method-args">(ref, options = nil)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Converts a data structure into an XML document.
+</p>
+<table>
+<tr><td valign="top">ref:</td><td>Reference to data structure to be converted into XML.
+
+</td></tr>
+<tr><td valign="top">options:</td><td>Options to be used.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+
+    </div>
+
+
+  </div>
+
+
+<div id="validator-badges">
+  <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000001.html b/docs/api/classes/XmlSimple.src/M000001.html
new file mode 100755
index 0000000..e862817
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000001.html
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>new (XmlSimple)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 128</span>
+  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">defaults</span> = <span class="ruby-keyword kw">nil</span>)
+    <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">defaults</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">||</span> <span class="ruby-identifier">defaults</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+      <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;Options have to be a Hash.&quot;</span>
+    <span class="ruby-keyword kw">end</span>
+    <span class="ruby-ivar">@default_options</span> = <span class="ruby-identifier">normalize_option_names</span>(<span class="ruby-identifier">defaults</span>, (<span class="ruby-constant">KNOWN_OPTIONS</span>[<span class="ruby-value str">'in'</span>] <span class="ruby-operator">+</span> <span class="ruby-constant">KNOWN_OPTIONS</span>[<span class="ruby-value str">'out'</span>]).<span class="ruby-identifier">uniq</span>)
+    <span class="ruby-ivar">@options</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span>
+    <span class="ruby-ivar">@_var_values</span> = <span class="ruby-keyword kw">nil</span>
+  <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000002.html b/docs/api/classes/XmlSimple.src/M000002.html
new file mode 100755
index 0000000..6a28bfd
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000002.html
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>xml_in (XmlSimple)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 149</span>
+  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">xml_in</span>(<span class="ruby-identifier">string</span> = <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+    <span class="ruby-identifier">handle_options</span>(<span class="ruby-value str">'in'</span>, <span class="ruby-identifier">options</span>)
+
+    <span class="ruby-comment cmt"># If no XML string or filename was supplied look for scriptname.xml.</span>
+    <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">nil?</span>
+      <span class="ruby-identifier">string</span> = <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">basename</span>(<span class="ruby-identifier">$0</span>)
+      <span class="ruby-identifier">string</span>.<span class="ruby-identifier">sub!</span>(<span class="ruby-regexp re">/\.[^.]+$/</span>, <span class="ruby-value str">''</span>)
+      <span class="ruby-identifier">string</span> <span class="ruby-operator">+=</span> <span class="ruby-value str">'.xml'</span>
+
+      <span class="ruby-identifier">directory</span> = <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">dirname</span>(<span class="ruby-identifier">$0</span>)
+      <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>].<span class="ruby-identifier">unshift</span>(<span class="ruby-identifier">directory</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">directory</span>.<span class="ruby-identifier">nil?</span>
+    <span class="ruby-keyword kw">end</span>
+
+    <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">String</span>)
+      <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">string</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/&lt;.*?&gt;/</span><span class="ruby-identifier">m</span>
+        <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">string</span>)
+      <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">string</span> <span class="ruby-operator">==</span> <span class="ruby-value str">'-'</span>
+        <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">$stdin</span>.<span class="ruby-identifier">readlines</span>.<span class="ruby-identifier">to_s</span>)
+      <span class="ruby-keyword kw">else</span>
+        <span class="ruby-identifier">filename</span> = <span class="ruby-identifier">find_xml_file</span>(<span class="ruby-identifier">string</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'searchpath'</span>])
+
+        <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'cache'</span>)
+          <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'cache'</span>].<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">scheme</span><span class="ruby-operator">|</span>
+            <span class="ruby-keyword kw">case</span>(<span class="ruby-identifier">scheme</span>)
+            <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'storable'</span>
+              <span class="ruby-identifier">content</span> = <span class="ruby-ivar">@@cache</span>.<span class="ruby-identifier">restore_storable</span>(<span class="ruby-identifier">filename</span>)
+            <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'mem_share'</span>
+              <span class="ruby-identifier">content</span> = <span class="ruby-ivar">@@cache</span>.<span class="ruby-identifier">restore_mem_share</span>(<span class="ruby-identifier">filename</span>)
+            <span class="ruby-keyword kw">when</span> <span class="ruby-value str">'mem_copy'</span>
+              <span class="ruby-identifier">content</span> = <span class="ruby-ivar">@@cache</span>.<span class="ruby-identifier">restore_mem_copy</span>(<span class="ruby-identifier">filename</span>)
+            <span class="ruby-keyword kw">else</span>
+              <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Unsupported caching scheme: &lt;#{scheme}&gt;.&quot;</span>
+            <span class="ruby-keyword kw">end</span>
+            <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">content</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">content</span>
+          }
+        <span class="ruby-keyword kw">end</span>
+        
+        <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">load_xml_file</span>(<span class="ruby-identifier">filename</span>)
+      <span class="ruby-keyword kw">end</span>
+    <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">IO</span>) <span class="ruby-operator">||</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">StringIO</span>)
+      <span class="ruby-ivar">@doc</span> = <span class="ruby-identifier">parse</span>(<span class="ruby-identifier">string</span>.<span class="ruby-identifier">readlines</span>.<span class="ruby-identifier">to_s</span>)
+    <span class="ruby-keyword kw">else</span>
+      <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;Could not parse object of type: &lt;#{string.type}&gt;.&quot;</span>
+    <span class="ruby-keyword kw">end</span>
+
+    <span class="ruby-identifier">result</span> = <span class="ruby-identifier">collapse</span>(<span class="ruby-ivar">@doc</span>.<span class="ruby-identifier">root</span>)
+    <span class="ruby-identifier">result</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keeproot'</span>] <span class="ruby-operator">?</span> <span class="ruby-identifier">merge</span>({}, <span class="ruby-ivar">@doc</span>.<span class="ruby-identifier">root</span>.<span class="ruby-identifier">name</span>, <span class="ruby-identifier">result</span>) <span class="ruby-operator">:</span> <span class="ruby-identifier">result</span>
+    <span class="ruby-identifier">put_into_cache</span>(<span class="ruby-identifier">result</span>, <span class="ruby-identifier">filename</span>)
+    <span class="ruby-identifier">result</span>
+  <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000003.html b/docs/api/classes/XmlSimple.src/M000003.html
new file mode 100755
index 0000000..1912fc2
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000003.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>xml_in (XmlSimple)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 201</span>
+  <span class="ruby-keyword kw">def</span> <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">xml_in</span>(<span class="ruby-identifier">string</span> = <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+    <span class="ruby-identifier">xml_simple</span> = <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">new</span>
+    <span class="ruby-identifier">xml_simple</span>.<span class="ruby-identifier">xml_in</span>(<span class="ruby-identifier">string</span>, <span class="ruby-identifier">options</span>)
+  <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000004.html b/docs/api/classes/XmlSimple.src/M000004.html
new file mode 100755
index 0000000..266cce5
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000004.html
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>xml_out (XmlSimple)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 212</span>
+  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">xml_out</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+    <span class="ruby-identifier">handle_options</span>(<span class="ruby-value str">'out'</span>, <span class="ruby-identifier">options</span>)
+    <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Array</span>)
+      <span class="ruby-identifier">ref</span> = { <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'anonymoustag'</span>] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">ref</span> }
+    <span class="ruby-keyword kw">end</span>
+
+    <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'keeproot'</span>]
+      <span class="ruby-identifier">keys</span> = <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">keys</span>
+      <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">keys</span>.<span class="ruby-identifier">size</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span>
+        <span class="ruby-identifier">ref</span> = <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">keys</span>[<span class="ruby-value">0</span>]]
+        <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>] = <span class="ruby-identifier">keys</span>[<span class="ruby-value">0</span>]
+      <span class="ruby-keyword kw">end</span>
+    <span class="ruby-keyword kw">elsif</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>] <span class="ruby-operator">==</span> <span class="ruby-value str">''</span>
+      <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">ref</span>.<span class="ruby-identifier">instance_of?</span>(<span class="ruby-constant">Hash</span>)
+        <span class="ruby-identifier">refsave</span> = <span class="ruby-identifier">ref</span>
+        <span class="ruby-identifier">ref</span> = {}
+        <span class="ruby-identifier">refsave</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
+          <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-identifier">scalar</span>(<span class="ruby-identifier">value</span>)
+            <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span>
+          <span class="ruby-keyword kw">else</span>
+            <span class="ruby-identifier">ref</span>[<span class="ruby-identifier">key</span>] = [ <span class="ruby-identifier">value</span>.<span class="ruby-identifier">to_s</span> ]
+          <span class="ruby-keyword kw">end</span>
+        }
+      <span class="ruby-keyword kw">end</span>
+    <span class="ruby-keyword kw">end</span>
+
+    <span class="ruby-ivar">@ancestors</span> = []
+    <span class="ruby-identifier">xml</span> = <span class="ruby-identifier">value_to_xml</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'rootname'</span>], <span class="ruby-value str">''</span>)
+    <span class="ruby-ivar">@ancestors</span> = <span class="ruby-keyword kw">nil</span>
+
+    <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'xmldeclaration'</span>]
+      <span class="ruby-identifier">xml</span> = <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'xmldeclaration'</span>] <span class="ruby-operator">+</span> <span class="ruby-value str">&quot;\n&quot;</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">xml</span>
+    <span class="ruby-keyword kw">end</span>
+
+    <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">has_key?</span>(<span class="ruby-value str">'outputfile'</span>)
+      <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'outputfile'</span>].<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">IO</span>)
+        <span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@options</span>[<span class="ruby-value str">'outputfile'</span>].<span class="ruby-identifier">write</span>(<span class="ruby-identifier">xml</span>)
+      <span class="ruby-keyword kw">else</span>
+        <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-ivar">@options</span>[<span class="ruby-value str">'outputfile'</span>], <span class="ruby-value str">&quot;w&quot;</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">file</span><span class="ruby-operator">|</span> <span class="ruby-identifier">file</span>.<span class="ruby-identifier">write</span>(<span class="ruby-identifier">xml</span>) }
+      <span class="ruby-keyword kw">end</span>
+    <span class="ruby-keyword kw">end</span>
+    <span class="ruby-identifier">xml</span>
+  <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000005.html b/docs/api/classes/XmlSimple.src/M000005.html
new file mode 100755
index 0000000..0f1197c
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000005.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>xml_out (XmlSimple)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 257</span>
+  <span class="ruby-keyword kw">def</span> <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">xml_out</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-identifier">options</span> = <span class="ruby-keyword kw">nil</span>)
+    <span class="ruby-identifier">xml_simple</span> = <span class="ruby-constant">XmlSimple</span>.<span class="ruby-identifier">new</span>
+    <span class="ruby-identifier">xml_simple</span>.<span class="ruby-identifier">xml_out</span>(<span class="ruby-identifier">hash</span>, <span class="ruby-identifier">options</span>)
+  <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000006.html b/docs/api/classes/XmlSimple.src/M000006.html
new file mode 100755
index 0000000..5c5f48c
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000006.html
@@ -0,0 +1,25 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>normalize_option_names (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 296</span>
+  <span class="kw">def</span> normalize_option_names(options, known_options)
+    <span class="kw">return</span> <span class="kw">nil</span> <span class="kw">if</span> options.nil?
+    result = Hash.new
+    options.each { |key, value|
+      lkey = key.downcase
+      lkey.gsub!(<span class="re">/_/</span>, <span class="str">''</span>)
+      <span class="kw">if</span> !known_options.member?(lkey)
+        raise ArgumentError, &quot;Unrecognised option: #{lkey}.&quot;
+      <span class="kw">end</span>
+      result[lkey] = value
+    }
+    result
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000007.html b/docs/api/classes/XmlSimple.src/M000007.html
new file mode 100755
index 0000000..51054d0
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000007.html
@@ -0,0 +1,147 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>handle_options (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 317</span>
+  <span class="kw">def</span> handle_options(direction, options)
+    @options = options || Hash.new
+
+    raise ArgumentError, <span class="str">&quot;Options must be a Hash!&quot;</span> <span class="kw">unless</span> @options.instance_of?(Hash)
+
+    <span class="kw">unless</span> KNOWN_OPTIONS.has_key?(direction)
+      raise ArgumentError, &quot;Unknown direction: &lt;#{direction}&gt;.&quot;
+    <span class="kw">end</span>
+
+    known_options = KNOWN_OPTIONS[direction]
+    @options = normalize_option_names(@options, known_options)
+
+    <span class="kw">unless</span> @default_options.nil?
+      known_options.each { |option|
+        <span class="kw">unless</span> @options.has_key?(option)
+          <span class="kw">if</span> @default_options.has_key?(option)
+            @options[option] = @default_options[option]
+          <span class="kw">end</span>
+        <span class="kw">end</span>
+      }
+    <span class="kw">end</span>
+
+    <span class="kw">unless</span> @options.has_key?(<span class="str">'noattr'</span>)
+        @options[<span class="str">'noattr'</span>] = <span class="kw">false</span>
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'rootname'</span>)
+      @options[<span class="str">'rootname'</span>] = <span class="str">''</span> <span class="kw">if</span> @options[<span class="str">'rootname'</span>].nil?
+    <span class="kw">else</span>
+      @options[<span class="str">'rootname'</span>] = DEF_ROOT_NAME
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'xmldeclaration'</span>) &amp;&amp; @options[<span class="str">'xmldeclaration'</span>] == <span class="kw">true</span>
+      @options[<span class="str">'xmldeclaration'</span>] = DEF_XML_DECLARATION
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'contentkey'</span>)
+      <span class="kw">if</span> @options[<span class="str">'contentkey'</span>] =~ <span class="re">/^-(.*)$/</span>
+        @options[<span class="str">'contentkey'</span>]    = $1
+        @options[<span class="str">'collapseagain'</span>] = <span class="kw">true</span>
+      <span class="kw">end</span>
+    <span class="kw">else</span>
+      @options[<span class="str">'contentkey'</span>] = DEF_CONTENT_KEY
+    <span class="kw">end</span>
+
+    <span class="kw">unless</span> @options.has_key?(<span class="str">'normalisespace'</span>)
+      @options[<span class="str">'normalisespace'</span>] = @options[<span class="str">'normalizespace'</span>]
+    <span class="kw">end</span>
+    @options[<span class="str">'normalisespace'</span>] = 0 <span class="kw">if</span> @options[<span class="str">'normalisespace'</span>].nil?
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'searchpath'</span>)
+      <span class="kw">unless</span> @options[<span class="str">'searchpath'</span>].instance_of?(Array)
+        @options[<span class="str">'searchpath'</span>] = [ @options[<span class="str">'searchpath'</span>] ]
+      <span class="kw">end</span>
+    <span class="kw">else</span>
+      @options[<span class="str">'searchpath'</span>] = []
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'cache'</span>) &amp;&amp; scalar(@options[<span class="str">'cache'</span>])
+      @options[<span class="str">'cache'</span>] = [ @options[<span class="str">'cache'</span>] ]
+    <span class="kw">end</span>
+
+    @options[<span class="str">'anonymoustag'</span>] = DEF_ANONYMOUS_TAG <span class="kw">unless</span> @options.has_key?(<span class="str">'anonymoustag'</span>)
+
+    <span class="kw">if</span> !@options.has_key?(<span class="str">'indent'</span>) || @options[<span class="str">'indent'</span>].nil?
+      @options[<span class="str">'indent'</span>] = DEF_INDENTATION
+    <span class="kw">end</span>
+
+    @options[<span class="str">'indent'</span>] = <span class="str">''</span> <span class="kw">if</span> @options.has_key?(<span class="str">'noindent'</span>)
+
+    <span class="cmt"># Special cleanup for 'keyattr' which could be an array or</span>
+    <span class="cmt"># a hash or left to default to array.</span>
+    <span class="kw">if</span> @options.has_key?(<span class="str">'keyattr'</span>)
+      <span class="kw">if</span> !scalar(@options[<span class="str">'keyattr'</span>])
+        <span class="cmt"># Convert keyattr =&gt; { elem =&gt; '+attr' }</span>
+        <span class="cmt">#      to keyattr =&gt; { elem =&gt; ['attr', '+'] }</span>
+        <span class="kw">if</span> @options[<span class="str">'keyattr'</span>].instance_of?(Hash)
+          @options[<span class="str">'keyattr'</span>].each { |key, value|
+            <span class="kw">if</span> value =~ <span class="re">/^([-+])?(.*)$/</span>
+              @options[<span class="str">'keyattr'</span>][key] = [$2, $1 ? $1 : <span class="str">''</span>]
+            <span class="kw">end</span>
+          }
+        <span class="kw">elsif</span> !@options[<span class="str">'keyattr'</span>].instance_of?(Array)
+          raise ArgumentError, <span class="str">&quot;'keyattr' must be String, Hash, or Array!&quot;</span>
+        <span class="kw">end</span>
+      <span class="kw">else</span>
+        @options[<span class="str">'keyattr'</span>] = [ @options[<span class="str">'keyattr'</span>] ]
+      <span class="kw">end</span>
+    <span class="kw">else</span>
+      @options[<span class="str">'keyattr'</span>] = DEF_KEY_ATTRIBUTES
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'forcearray'</span>)
+      <span class="kw">if</span> @options[<span class="str">'forcearray'</span>].instance_of?(Regexp)
+        @options[<span class="str">'forcearray'</span>] = [ @options[<span class="str">'forcearray'</span>] ]
+      <span class="kw">end</span>
+
+      <span class="kw">if</span> @options[<span class="str">'forcearray'</span>].instance_of?(Array)
+        force_list = @options[<span class="str">'forcearray'</span>]
+        <span class="kw">unless</span> force_list.empty?
+          @options[<span class="str">'forcearray'</span>] = {}
+          force_list.each { |tag|
+            <span class="kw">if</span> tag.instance_of?(Regexp)
+              <span class="kw">unless</span> @options[<span class="str">'forcearray'</span>][<span class="str">'_regex'</span>].instance_of?(Array)
+                @options[<span class="str">'forcearray'</span>][<span class="str">'_regex'</span>] = []
+              <span class="kw">end</span>
+              @options[<span class="str">'forcearray'</span>][<span class="str">'_regex'</span>] &lt;&lt; tag
+            <span class="kw">else</span>
+              @options[<span class="str">'forcearray'</span>][tag] = <span class="kw">true</span>
+            <span class="kw">end</span>
+          }
+        <span class="kw">else</span>
+          @options[<span class="str">'forcearray'</span>] = <span class="kw">false</span>
+        <span class="kw">end</span>
+      <span class="kw">else</span>
+        @options[<span class="str">'forcearray'</span>] = @options[<span class="str">'forcearray'</span>] ? <span class="kw">true</span> : <span class="kw">false</span>
+      <span class="kw">end</span>
+    <span class="kw">else</span>
+      @options[<span class="str">'forcearray'</span>] = DEF_FORCE_ARRAY
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'grouptags'</span>) &amp;&amp; !@options[<span class="str">'grouptags'</span>].instance_of?(Hash)
+      raise ArgumentError, <span class="str">&quot;Illegal value for 'GroupTags' option - expected a Hash.&quot;</span>
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'variables'</span>) &amp;&amp; !@options[<span class="str">'variables'</span>].instance_of?(Hash)
+      raise ArgumentError, <span class="str">&quot;Illegal value for 'Variables' option - expected a Hash.&quot;</span>
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> @options.has_key?(<span class="str">'variables'</span>)
+      @_var_values = @options[<span class="str">'variables'</span>]
+    <span class="kw">elsif</span> @options.has_key?(<span class="str">'varattr'</span>)
+      @_var_values = {}
+    <span class="kw">end</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000008.html b/docs/api/classes/XmlSimple.src/M000008.html
new file mode 100755
index 0000000..57d45dd
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000008.html
@@ -0,0 +1,65 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>collapse (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 457</span>
+  <span class="kw">def</span> collapse(element)
+    result = @options[<span class="str">'noattr'</span>] ? {} : get_attributes(element)
+
+    <span class="kw">if</span> @options[<span class="str">'normalisespace'</span>] == 2
+      result.each { |k, v| result[k] = normalise_space(v) }
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> element.has_elements?
+      element.each_element { |child|
+        value = collapse(child)
+        <span class="kw">if</span> empty(value) &amp;&amp; (element.attributes.empty? || @options[<span class="str">'noattr'</span>])
+          <span class="kw">next</span> <span class="kw">if</span> @options.has_key?(<span class="str">'suppressempty'</span>) &amp;&amp; @options[<span class="str">'suppressempty'</span>] == <span class="kw">true</span>
+        <span class="kw">end</span>
+        result = merge(result, child.name, value)
+      }
+      <span class="kw">if</span> has_mixed_content?(element)
+        <span class="cmt"># normalisespace?</span>
+        content = element.texts.map { |x| x.to_s }
+        content = content[0] <span class="kw">if</span> content.size == 1
+        result[@options[<span class="str">'contentkey'</span>]] = content
+      <span class="kw">end</span>
+    <span class="kw">elsif</span> element.has_text? <span class="cmt"># i.e. it has only text.</span>
+      <span class="kw">return</span> collapse_text_node(result, element)
+    <span class="kw">end</span>
+
+    <span class="cmt"># Turn Arrays into Hashes if key fields present.</span>
+    count = fold_arrays(result)
+
+    <span class="cmt"># Disintermediate grouped tags.</span>
+    <span class="kw">if</span> @options.has_key?(<span class="str">'grouptags'</span>)
+      result.each { |key, value|
+        <span class="kw">next</span> <span class="kw">unless</span> (value.instance_of?(Hash) &amp;&amp; (value.size == 1))
+        child_key, child_value = value.to_a[0]
+        <span class="kw">if</span> @options[<span class="str">'grouptags'</span>][key] == child_key
+          result[key] = child_value
+        <span class="kw">end</span>
+      }
+    <span class="kw">end</span>
+    
+    <span class="cmt"># Fold Hases containing a single anonymous Array up into just the Array.</span>
+    <span class="kw">if</span> count == 1 
+      anonymoustag = @options[<span class="str">'anonymoustag'</span>]
+      <span class="kw">if</span> result.has_key?(anonymoustag) &amp;&amp; result[anonymoustag].instance_of?(Array)
+        <span class="kw">return</span> result[anonymoustag]
+      <span class="kw">end</span>
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> result.empty? &amp;&amp; @options.has_key?(<span class="str">'suppressempty'</span>)
+      <span class="kw">return</span> @options[<span class="str">'suppressempty'</span>] == <span class="str">''</span> ? <span class="str">''</span> : <span class="kw">nil</span>
+    <span class="kw">end</span>
+
+    result
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000009.html b/docs/api/classes/XmlSimple.src/M000009.html
new file mode 100755
index 0000000..1ab96d9
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000009.html
@@ -0,0 +1,28 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>collapse_text_node (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 519</span>
+  <span class="kw">def</span> collapse_text_node(hash, element)
+    value = node_to_text(element)
+    <span class="kw">if</span> empty(value) &amp;&amp; !element.has_attributes?
+      <span class="kw">return</span> {}
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> element.has_attributes? &amp;&amp; !@options[<span class="str">'noattr'</span>]
+      <span class="kw">return</span> merge(hash, @options[<span class="str">'contentkey'</span>], value)
+    <span class="kw">else</span>
+      <span class="kw">if</span> @options[<span class="str">'forcecontent'</span>]
+        <span class="kw">return</span> merge(hash, @options[<span class="str">'contentkey'</span>], value)
+      <span class="kw">else</span>
+        <span class="kw">return</span> value
+      <span class="kw">end</span>
+    <span class="kw">end</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000010.html b/docs/api/classes/XmlSimple.src/M000010.html
new file mode 100755
index 0000000..7b55309
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000010.html
@@ -0,0 +1,29 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>fold_arrays (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 540</span>
+  <span class="kw">def</span> fold_arrays(hash)
+    fold_amount = 0
+    keyattr = @options[<span class="str">'keyattr'</span>]
+    <span class="kw">if</span> (keyattr.instance_of?(Array) || keyattr.instance_of?(Hash))
+      hash.each { |key, value|
+        <span class="kw">if</span> value.instance_of?(Array)
+          <span class="kw">if</span> keyattr.instance_of?(Array)
+            hash[key] = fold_array(value)
+          <span class="kw">else</span>
+            hash[key] = fold_array_by_name(key, value)
+          <span class="kw">end</span>
+          fold_amount += 1
+        <span class="kw">end</span>
+      }
+    <span class="kw">end</span>
+    fold_amount
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000011.html b/docs/api/classes/XmlSimple.src/M000011.html
new file mode 100755
index 0000000..4aab382
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000011.html
@@ -0,0 +1,33 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>fold_array (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 564</span>
+  <span class="kw">def</span> fold_array(array)
+    hash = Hash.new
+    array.each { |x|
+      <span class="kw">return</span> array <span class="kw">unless</span> x.instance_of?(Hash)
+      key_matched = <span class="kw">false</span>
+      @options[<span class="str">'keyattr'</span>].each { |key|
+        <span class="kw">if</span> x.has_key?(key)
+          key_matched = <span class="kw">true</span>
+          value = x[key]
+          <span class="kw">return</span> array <span class="kw">if</span> value.instance_of?(Hash) || value.instance_of?(Array)
+          value = normalise_space(value) <span class="kw">if</span> @options[<span class="str">'normalisespace'</span>] == 1
+          x.delete(key)
+          hash[value] = x
+          <span class="kw">break</span>
+        <span class="kw">end</span>
+      }
+      <span class="kw">return</span> array <span class="kw">unless</span> key_matched
+    }
+    hash = collapse_content(hash) <span class="kw">if</span> @options[<span class="str">'collapseagain'</span>]
+    hash
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000012.html b/docs/api/classes/XmlSimple.src/M000012.html
new file mode 100755
index 0000000..91feb29
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000012.html
@@ -0,0 +1,33 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>fold_array_by_name (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 594</span>
+  <span class="kw">def</span> fold_array_by_name(name, array)
+    <span class="kw">return</span> array <span class="kw">unless</span> @options[<span class="str">'keyattr'</span>].has_key?(name)
+    key, flag = @options[<span class="str">'keyattr'</span>][name]
+
+    hash = Hash.new
+    array.each { |x|
+      <span class="kw">if</span> x.instance_of?(Hash) &amp;&amp; x.has_key?(key)
+        value = x[key]
+        <span class="kw">return</span> array <span class="kw">if</span> value.instance_of?(Hash) || value.instance_of?(Array)
+        value = normalise_space(value) <span class="kw">if</span> @options[<span class="str">'normalisespace'</span>] == 1
+        hash[value] = x
+        hash[value][&quot;-#{key}&quot;] = hash[value][key] <span class="kw">if</span> flag == <span class="str">'-'</span>
+        hash[value].delete(key) <span class="kw">unless</span> flag == <span class="str">'+'</span>
+      <span class="kw">else</span>
+        $stderr.puts(&quot;Warning: &lt;#{name}&gt; element has no '#{key}' attribute.&quot;)
+        <span class="kw">return</span> array
+      <span class="kw">end</span>
+    }
+    hash = collapse_content(hash) <span class="kw">if</span> @options[<span class="str">'collapseagain'</span>]
+    hash
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000013.html b/docs/api/classes/XmlSimple.src/M000013.html
new file mode 100755
index 0000000..87464e5
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000013.html
@@ -0,0 +1,20 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>collapse_content (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 620</span>
+  <span class="kw">def</span> collapse_content(hash)
+    content_key = @options[<span class="str">'contentkey'</span>]
+    hash.each_value { |value|
+      <span class="kw">return</span> hash <span class="kw">unless</span> value.instance_of?(Hash) &amp;&amp; value.size == 1 &amp;&amp; value.has_key?(content_key)
+      hash.each_key { |key| hash[key] = hash[key][content_key] }
+    }
+    hash
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000014.html b/docs/api/classes/XmlSimple.src/M000014.html
new file mode 100755
index 0000000..2f0e285
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000014.html
@@ -0,0 +1,46 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>merge (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 640</span>
+  <span class="kw">def</span> merge(hash, key, value)
+    <span class="kw">if</span> value.instance_of?(String)
+      value = normalise_space(value) <span class="kw">if</span> @options[<span class="str">'normalisespace'</span>] == 2
+
+      <span class="cmt"># do variable substitutions</span>
+      <span class="kw">unless</span> @_var_values.nil? || @_var_values.empty?
+        value.gsub!(<span class="re">/\$\{(\w+)\}/</span>) { |x| get_var($1) }
+      <span class="kw">end</span>
+      
+      <span class="cmt"># look for variable definitions</span>
+      <span class="kw">if</span> @options.has_key?(<span class="str">'varattr'</span>)
+        varattr = @options[<span class="str">'varattr'</span>]
+        <span class="kw">if</span> hash.has_key?(varattr)
+          set_var(hash[varattr], value)
+        <span class="kw">end</span>
+      <span class="kw">end</span>
+    <span class="kw">end</span>
+    <span class="kw">if</span> hash.has_key?(key)
+      <span class="kw">if</span> hash[key].instance_of?(Array)
+        hash[key] &lt;&lt; value
+      <span class="kw">else</span>
+        hash[key] = [ hash[key], value ]
+      <span class="kw">end</span>
+    <span class="kw">elsif</span> value.instance_of?(Array) <span class="cmt"># Handle anonymous arrays.</span>
+      hash[key] = [ value ]
+    <span class="kw">else</span>
+      <span class="kw">if</span> force_array?(key)
+        hash[key] = [ value ]
+      <span class="kw">else</span>
+        hash[key] = value
+      <span class="kw">end</span>
+    <span class="kw">end</span>
+    hash
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000015.html b/docs/api/classes/XmlSimple.src/M000015.html
new file mode 100755
index 0000000..c4c82a2
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000015.html
@@ -0,0 +1,23 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>force_array? (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 677</span>
+  <span class="kw">def</span> force_array?(key)
+    <span class="kw">return</span> <span class="kw">false</span> <span class="kw">if</span> key == @options[<span class="str">'contentkey'</span>]
+    <span class="kw">return</span> <span class="kw">true</span> <span class="kw">if</span> @options[<span class="str">'forcearray'</span>] == <span class="kw">true</span>
+    forcearray = @options[<span class="str">'forcearray'</span>]
+    <span class="kw">if</span> forcearray.instance_of?(Hash)
+      <span class="kw">return</span> <span class="kw">true</span> <span class="kw">if</span> forcearray.has_key?(key) 
+      <span class="kw">return</span> <span class="kw">false</span> <span class="kw">unless</span> forcearray.has_key?(<span class="str">'_regex'</span>)
+      forcearray[<span class="str">'_regex'</span>].each { |x| <span class="kw">return</span> <span class="kw">true</span> <span class="kw">if</span> key =~ x }
+    <span class="kw">end</span>
+    <span class="kw">return</span> <span class="kw">false</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000016.html b/docs/api/classes/XmlSimple.src/M000016.html
new file mode 100755
index 0000000..ad7c63c
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000016.html
@@ -0,0 +1,17 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>get_attributes (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 694</span>
+  <span class="kw">def</span> get_attributes(node)
+    attributes = {}
+    node.attributes.each { |n,v| attributes[n] = v }
+    attributes
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000017.html b/docs/api/classes/XmlSimple.src/M000017.html
new file mode 100755
index 0000000..da0617c
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000017.html
@@ -0,0 +1,18 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>has_mixed_content? (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 704</span>
+  <span class="kw">def</span> has_mixed_content?(element)
+    <span class="kw">if</span> element.has_text? &amp;&amp; element.has_elements?
+      <span class="kw">return</span> <span class="kw">true</span> <span class="kw">if</span> element.texts.join(<span class="str">''</span>) !~ <span class="re">/^\s*$/s</span>
+    <span class="kw">end</span>
+    <span class="kw">false</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000018.html b/docs/api/classes/XmlSimple.src/M000018.html
new file mode 100755
index 0000000..8587db5
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000018.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>set_var (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 715</span>
+  <span class="kw">def</span> set_var(name, value)
+    @_var_values[name] = value
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000019.html b/docs/api/classes/XmlSimple.src/M000019.html
new file mode 100755
index 0000000..d268bfa
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000019.html
@@ -0,0 +1,19 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>get_var (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 721</span>
+  <span class="kw">def</span> get_var(name)
+    <span class="kw">if</span> @_var_values.has_key?(name)
+      <span class="kw">return</span> @_var_values[name]
+    <span class="kw">else</span>
+      <span class="kw">return</span> &quot;${#{name}}&quot;
+    <span class="kw">end</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000020.html b/docs/api/classes/XmlSimple.src/M000020.html
new file mode 100755
index 0000000..c8e72e3
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000020.html
@@ -0,0 +1,117 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>value_to_xml (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 738</span>
+  <span class="kw">def</span> value_to_xml(ref, name, indent)
+    named = !name.nil? &amp;&amp; name != <span class="str">''</span>
+    nl    = @options.has_key?(<span class="str">'noindent'</span>) ? <span class="str">''</span> : <span class="str">&quot;\n&quot;</span>
+
+    <span class="kw">if</span> !scalar(ref)
+      <span class="kw">if</span> @ancestors.member?(ref)
+        raise ArgumentError, <span class="str">&quot;Circular data structures not supported!&quot;</span>
+      <span class="kw">end</span>
+      @ancestors &lt;&lt; ref
+    <span class="kw">else</span>
+      <span class="kw">if</span> named
+        <span class="kw">return</span> [indent, <span class="str">'&lt;'</span>, name, <span class="str">'&gt;'</span>, @options[<span class="str">'noescape'</span>] ? ref.to_s : escape_value(ref.to_s), <span class="str">'&lt;/'</span>, name, <span class="str">'&gt;'</span>, nl].join(<span class="str">''</span>)
+      <span class="kw">else</span>
+        <span class="kw">return</span> ref.to_s + nl
+      <span class="kw">end</span>
+    <span class="kw">end</span>
+
+    <span class="cmt"># Unfold hash to array if possible.</span>
+    <span class="kw">if</span> ref.instance_of?(Hash) &amp;&amp; !ref.empty? &amp;&amp; !@options[<span class="str">'keyattr'</span>].empty? &amp;&amp; indent != <span class="str">''</span>
+      ref = hash_to_array(name, ref)
+    <span class="kw">end</span>
+
+    result = []
+    <span class="kw">if</span> ref.instance_of?(Hash)
+      <span class="cmt"># Reintermediate grouped values if applicable.</span>
+      <span class="kw">if</span> @options.has_key?(<span class="str">'grouptags'</span>)
+        ref.each { |key, value|
+          <span class="kw">if</span> @options[<span class="str">'grouptags'</span>].has_key?(key)
+            ref[key] = { @options[<span class="str">'grouptags'</span>][key] =&gt; value }
+          <span class="kw">end</span>
+        }
+      <span class="kw">end</span>
+      
+      nested = []
+      text_content = <span class="kw">nil</span>
+      <span class="kw">if</span> named
+        result &lt;&lt; indent &lt;&lt; <span class="str">'&lt;'</span> &lt;&lt; name
+      <span class="kw">end</span>
+
+      <span class="kw">if</span> !ref.empty?
+        ref.each { |key, value|
+          <span class="kw">next</span> <span class="kw">if</span> !key.nil? &amp;&amp; key[0, 1] == <span class="str">'-'</span>
+          <span class="kw">if</span> value.nil?
+            <span class="kw">unless</span> @options.has_key?(<span class="str">'suppressempty'</span>) &amp;&amp; @options[<span class="str">'suppressempty'</span>].nil?
+              raise ArgumentError, <span class="str">&quot;Use of uninitialized value!&quot;</span>
+            <span class="kw">end</span>
+            value = {}
+          <span class="kw">end</span>
+
+          <span class="kw">if</span> !scalar(value) || @options[<span class="str">'noattr'</span>]
+            nested &lt;&lt; value_to_xml(value, key, indent + @options[<span class="str">'indent'</span>])
+          <span class="kw">else</span>
+            value = value.to_s
+            value = escape_value(value) <span class="kw">unless</span> @options[<span class="str">'noescape'</span>]
+            <span class="kw">if</span> key == @options[<span class="str">'contentkey'</span>]
+              text_content = value
+            <span class="kw">else</span>
+              result &lt;&lt; <span class="str">' '</span> &lt;&lt; key &lt;&lt; <span class="str">'=&quot;'</span> &lt;&lt; value &lt;&lt; <span class="str">'&quot;'</span>
+            <span class="kw">end</span>
+          <span class="kw">end</span>
+        }
+      <span class="kw">else</span>
+        text_content = <span class="str">''</span>
+      <span class="kw">end</span>
+
+      <span class="kw">if</span> !nested.empty? || !text_content.nil?
+        <span class="kw">if</span> named
+          result &lt;&lt; <span class="str">'&gt;'</span>
+          <span class="kw">if</span> !text_content.nil?
+            result &lt;&lt; text_content
+            nested[0].sub!(<span class="re">/^\s+/</span>, <span class="str">''</span>) <span class="kw">if</span> !nested.empty?
+          <span class="kw">else</span>
+            result &lt;&lt; nl
+          <span class="kw">end</span>
+          <span class="kw">if</span> !nested.empty?
+            result &lt;&lt; nested &lt;&lt; indent
+          <span class="kw">end</span>
+          result &lt;&lt; <span class="str">'&lt;/'</span> &lt;&lt; name &lt;&lt; <span class="str">'&gt;'</span> &lt;&lt; nl
+        <span class="kw">else</span>
+          result &lt;&lt; nested
+        <span class="kw">end</span>
+      <span class="kw">else</span>
+        result &lt;&lt; <span class="str">' /&gt;'</span> &lt;&lt; nl
+      <span class="kw">end</span>
+    <span class="kw">elsif</span> ref.instance_of?(Array)
+      ref.each { |value|
+        <span class="kw">if</span> scalar(value)
+          result &lt;&lt; indent &lt;&lt; <span class="str">'&lt;'</span> &lt;&lt; name &lt;&lt; <span class="str">'&gt;'</span>
+          result &lt;&lt; (@options[<span class="str">'noescape'</span>] ? value.to_s : escape_value(value.to_s))
+          result &lt;&lt; <span class="str">'&lt;/'</span> &lt;&lt; name &lt;&lt; <span class="str">'&gt;'</span> &lt;&lt; nl
+        <span class="kw">elsif</span> value.instance_of?(Hash)
+          result &lt;&lt; value_to_xml(value, name, indent)
+        <span class="kw">else</span>
+          result &lt;&lt; indent &lt;&lt; <span class="str">'&lt;'</span> &lt;&lt; name &lt;&lt; <span class="str">'&gt;'</span> &lt;&lt; nl
+          result &lt;&lt; value_to_xml(value, @options[<span class="str">'anonymoustag'</span>], indent + @options[<span class="str">'indent'</span>])
+          result &lt;&lt; indent &lt;&lt; <span class="str">'&lt;/'</span> &lt;&lt; name &lt;&lt; <span class="str">'&gt;'</span> &lt;&lt; nl
+        <span class="kw">end</span>
+      }
+    <span class="kw">else</span>
+      <span class="cmt"># Probably, this is obsolete.</span>
+      raise ArgumentError, &quot;Can't encode a value of type: #{ref.type}.&quot;
+    <span class="kw">end</span>
+    @ancestors.pop <span class="kw">if</span> !scalar(ref)
+    result.join(<span class="str">''</span>)
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000021.html b/docs/api/classes/XmlSimple.src/M000021.html
new file mode 100755
index 0000000..5ef2d39
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000021.html
@@ -0,0 +1,16 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>scalar (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 849</span>
+  <span class="kw">def</span> scalar(value)
+    <span class="kw">return</span> <span class="kw">false</span> <span class="kw">if</span> value.instance_of?(Hash) || value.instance_of?(Array)
+    <span class="kw">return</span> <span class="kw">true</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000022.html b/docs/api/classes/XmlSimple.src/M000022.html
new file mode 100755
index 0000000..cff134f
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000022.html
@@ -0,0 +1,26 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>hash_to_array (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 862</span>
+  <span class="kw">def</span> hash_to_array(parent, hashref)
+    arrayref = []
+    hashref.each { |key, value|
+      <span class="kw">return</span> hashref <span class="kw">unless</span> value.instance_of?(Hash)
+
+      <span class="kw">if</span> @options[<span class="str">'keyattr'</span>].instance_of?(Hash)
+        <span class="kw">return</span> hashref <span class="kw">unless</span> @options[<span class="str">'keyattr'</span>].has_key?(parent)
+        arrayref &lt;&lt; { @options[<span class="str">'keyattr'</span>][parent][0] =&gt; key }.update(value)
+      <span class="kw">else</span>
+        arrayref &lt;&lt; { @options[<span class="str">'keyattr'</span>][0] =&gt; key }.update(value)
+      <span class="kw">end</span>
+    }
+    arrayref
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000023.html b/docs/api/classes/XmlSimple.src/M000023.html
new file mode 100755
index 0000000..420a5ee
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000023.html
@@ -0,0 +1,22 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>escape_value (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 881</span>
+  <span class="kw">def</span> escape_value(data)
+    <span class="kw">return</span> data <span class="kw">if</span> data.nil? || data == <span class="str">''</span>
+    result = data.dup
+    result.gsub!(<span class="str">'&amp;'</span>, <span class="str">'&amp;amp;'</span>)
+    result.gsub!(<span class="str">'&lt;'</span>, <span class="str">'&amp;lt;'</span>)
+    result.gsub!(<span class="str">'&gt;'</span>, <span class="str">'&amp;gt;'</span>)
+    result.gsub!(<span class="str">'&quot;'</span>, <span class="str">'&amp;quot;'</span>)
+    result.gsub!(<span class="str">&quot;'&quot;</span>, <span class="str">'&amp;apos;'</span>)
+    result
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000024.html b/docs/api/classes/XmlSimple.src/M000024.html
new file mode 100755
index 0000000..9f8ee73
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000024.html
@@ -0,0 +1,18 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>normalise_space (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 897</span>
+  <span class="kw">def</span> normalise_space(text)
+    text.sub!(<span class="re">/^\s+/</span>, <span class="str">''</span>)
+    text.sub!(<span class="re">/\s+$/</span>, <span class="str">''</span>)
+    text.gsub!(<span class="re">/\s\s+/</span>, <span class="str">' '</span>)
+    text
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000025.html b/docs/api/classes/XmlSimple.src/M000025.html
new file mode 100755
index 0000000..2b17be3
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000025.html
@@ -0,0 +1,22 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>empty (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 909</span>
+  <span class="kw">def</span> empty(value)
+    <span class="kw">case</span> value
+      <span class="kw">when</span> Hash
+        <span class="kw">return</span> value.empty?
+      <span class="kw">when</span> String
+        <span class="kw">return</span> value !~ <span class="re">/\S/</span>m
+      <span class="kw">else</span>
+        <span class="kw">return</span> value.nil?
+    <span class="kw">end</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000026.html b/docs/api/classes/XmlSimple.src/M000026.html
new file mode 100755
index 0000000..838a1fc
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000026.html
@@ -0,0 +1,23 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>node_to_text (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 928</span>
+  <span class="kw">def</span> node_to_text(node, default = <span class="kw">nil</span>)
+    <span class="kw">if</span> node.instance_of?(Element) 
+      <span class="kw">return</span> node.texts.join(<span class="str">''</span>)
+    <span class="kw">elsif</span> node.instance_of?(Attribute)
+      <span class="kw">return</span> node.value.nil? ? default : node.value.strip
+    <span class="kw">elsif</span> node.instance_of?(Text)
+      <span class="kw">return</span> node.to_s.strip
+    <span class="kw">else</span>
+      <span class="kw">return</span> default
+    <span class="kw">end</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000027.html b/docs/api/classes/XmlSimple.src/M000027.html
new file mode 100755
index 0000000..06d8006
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000027.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>parse (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 949</span>
+  <span class="kw">def</span> parse(xml_string)
+    Document.new(xml_string)
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000028.html b/docs/api/classes/XmlSimple.src/M000028.html
new file mode 100755
index 0000000..a4f9c22
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000028.html
@@ -0,0 +1,30 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>find_xml_file (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 961</span>
+  <span class="kw">def</span> find_xml_file(file, searchpath)
+    filename = File::basename(file)
+
+    <span class="kw">if</span> filename != file
+      <span class="kw">return</span> file <span class="kw">if</span> File::file?(file)
+    <span class="kw">else</span>
+      searchpath.each { |path|
+        full_path = File::join(path, filename)
+        <span class="kw">return</span> full_path <span class="kw">if</span> File::file?(full_path)
+      }
+    <span class="kw">end</span>
+
+    <span class="kw">if</span> searchpath.empty?
+      <span class="kw">return</span> file <span class="kw">if</span> File::file?(file)
+      raise ArgumentError, &quot;File does not exist: #{file}.&quot;
+    <span class="kw">end</span>
+    raise ArgumentError, &quot;Could not find &lt;#{filename}&gt; in &lt;#{searchpath.join(':')}&gt;&quot;
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000029.html b/docs/api/classes/XmlSimple.src/M000029.html
new file mode 100755
index 0000000..2f02c74
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000029.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>load_xml_file (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 991</span>
+  <span class="kw">def</span> load_xml_file(filename)
+    parse(File.readlines(filename).to_s)
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple.src/M000030.html b/docs/api/classes/XmlSimple.src/M000030.html
new file mode 100755
index 0000000..5110f2d
--- /dev/null
+++ b/docs/api/classes/XmlSimple.src/M000030.html
@@ -0,0 +1,28 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>put_into_cache (XmlSimple)</title>
+<link rel=StyleSheet href="../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 1001</span>
+  <span class="kw">def</span> put_into_cache(data, filename)
+    <span class="kw">if</span> @options.has_key?(<span class="str">'cache'</span>)
+      @options[<span class="str">'cache'</span>].each { |scheme|
+        <span class="kw">case</span>(scheme)
+        <span class="kw">when</span> <span class="str">'storable'</span>
+          @@cache.save_storable(data, filename)
+        <span class="kw">when</span> <span class="str">'mem_share'</span>
+          @@cache.save_mem_share(data, filename)
+        <span class="kw">when</span> <span class="str">'mem_copy'</span>
+          @@cache.save_mem_copy(data, filename)
+        <span class="kw">else</span>
+          raise ArgumentError, &quot;Unsupported caching scheme: &lt;#{scheme}&gt;.&quot;
+        <span class="kw">end</span>
+      }
+    <span class="kw">end</span>
+  <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.html b/docs/api/classes/XmlSimple/Cache.html
new file mode 100755
index 0000000..63a19da
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.html
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>Class: XmlSimple::Cache</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <meta http-equiv="Content-Script-Type" content="text/javascript" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+  <script type="text/javascript">
+  // <![CDATA[
+
+  function popupCode( url ) {
+    window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+  }
+
+  function toggleCode( id ) {
+    if ( document.getElementById )
+      elem = document.getElementById( id );
+    else if ( document.all )
+      elem = eval( "document.all." + id );
+    else
+      return false;
+
+    elemStyle = elem.style;
+    
+    if ( elemStyle.display != "block" ) {
+      elemStyle.display = "block"
+    } else {
+      elemStyle.display = "none"
+    }
+
+    return true;
+  }
+  
+  // Make codeblocks hidden by default
+  document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
+  
+  // ]]>
+  </script>
+
+</head>
+<body>
+
+
+
+    <div id="classHeader">
+        <table class="header-table">
+        <tr class="top-aligned-row">
+          <td><strong>Class</strong></td>
+          <td class="class-name-in-header">XmlSimple::Cache</td>
+        </tr>
+        <tr class="top-aligned-row">
+            <td><strong>In:</strong></td>
+            <td>
+                <a href="../../files/lib/xmlsimple_rb.html">
+                lib/xmlsimple.rb
+                </a>
+        <br />
+            </td>
+        </tr>
+
+        <tr class="top-aligned-row">
+            <td><strong>Parent:</strong></td>
+            <td>
+                Object
+            </td>
+        </tr>
+        </table>
+    </div>
+  <!-- banner header -->
+
+  <div id="bodyContent">
+
+
+
+  <div id="contextContent">
+
+    <div id="description">
+      <p>
+A simple cache for XML documents that were already transformed by xml_in.
+</p>
+
+    </div>
+
+
+   </div>
+
+    <div id="method-list">
+      <h3 class="section-bar">Methods</h3>
+
+      <div class="name-list">
+      <a href="#M000006">new</a>&nbsp;&nbsp;
+      <a href="#M000012">restore_mem_copy</a>&nbsp;&nbsp;
+      <a href="#M000010">restore_mem_share</a>&nbsp;&nbsp;
+      <a href="#M000008">restore_storable</a>&nbsp;&nbsp;
+      <a href="#M000011">save_mem_copy</a>&nbsp;&nbsp;
+      <a href="#M000009">save_mem_share</a>&nbsp;&nbsp;
+      <a href="#M000007">save_storable</a>&nbsp;&nbsp;
+      </div>
+    </div>
+
+  </div>
+
+
+    <!-- if includes -->
+
+    <div id="section">
+
+
+
+
+
+      
+
+
+    <!-- if method_list -->
+    <div id="methods">
+      <h3 class="section-bar">Public Class methods</h3>
+
+      <div id="method-M000006" class="method-detail">
+        <a name="M000006"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000006.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000006.html');return false;">
+          <span class="method-name">new</span><span class="method-args">()</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Creates and initializes a <a href="Cache.html#M000006">new</a> <a
+href="Cache.html">Cache</a> object.
+</p>
+        </div>
+      </div>
+
+      <h3 class="section-bar">Public Instance methods</h3>
+
+      <div id="method-M000012" class="method-detail">
+        <a name="M000012"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000012.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000012.html');return false;">
+          <span class="method-name">restore_mem_copy</span><span class="method-args">(filename)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Restores a data structure from a memory cache. If restoring the data
+structure failed for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename:</td><td>Name of the file belonging to the data structure.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000010" class="method-detail">
+        <a name="M000010"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000010.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000010.html');return false;">
+          <span class="method-name">restore_mem_share</span><span class="method-args">(filename)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Restores a data structure from a shared memory cache. You should consider
+these elements as &quot;read only&quot;. If restoring the data structure
+failed for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename:</td><td>Name of the file belonging to the data structure.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000008" class="method-detail">
+        <a name="M000008"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000008.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000008.html');return false;">
+          <span class="method-name">restore_storable</span><span class="method-args">(filename)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Restores a data structure from a file. If restoring the data structure
+failed for any reason, nil will be returned.
+</p>
+<table>
+<tr><td valign="top">filename:</td><td>Name of the file belonging to the data structure.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000011" class="method-detail">
+        <a name="M000011"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000011.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000011.html');return false;">
+          <span class="method-name">save_mem_copy</span><span class="method-args">(data, filename)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Copies a data structure to a memory cache.
+</p>
+<table>
+<tr><td valign="top">data:</td><td>Data structure to be copied.
+
+</td></tr>
+<tr><td valign="top">filename:</td><td>Name of the file belonging to the data structure.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000009" class="method-detail">
+        <a name="M000009"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000009.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000009.html');return false;">
+          <span class="method-name">save_mem_share</span><span class="method-args">(data, filename)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Saves a data structure in a shared memory cache.
+</p>
+<table>
+<tr><td valign="top">data:</td><td>Data structure to be saved.
+
+</td></tr>
+<tr><td valign="top">filename:</td><td>Name of the file belonging to the data structure.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+      <div id="method-M000007" class="method-detail">
+        <a name="M000007"></a>
+
+        <div class="method-heading">
+          <a href="Cache.src/M000007.html" target="Code" class="method-signature"
+            onclick="popupCode('Cache.src/M000007.html');return false;">
+          <span class="method-name">save_storable</span><span class="method-args">(data, filename)</span>
+          </a>
+        </div>
+      
+        <div class="method-description">
+          <p>
+Saves a data structure into a file.
+</p>
+<table>
+<tr><td valign="top">data:</td><td>Data structure to be saved.
+
+</td></tr>
+<tr><td valign="top">filename:</td><td>Name of the file belonging to the data structure.
+
+</td></tr>
+</table>
+        </div>
+      </div>
+
+
+    </div>
+
+
+  </div>
+
+
+<div id="validator-badges">
+  <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000006.html b/docs/api/classes/XmlSimple/Cache.src/M000006.html
new file mode 100755
index 0000000..f4469d3
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000006.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>new (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 20</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>
+      <span class="ruby-ivar">@mem_share_cache</span> = {}
+      <span class="ruby-ivar">@mem_copy_cache</span>  = {}
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000007.html b/docs/api/classes/XmlSimple/Cache.src/M000007.html
new file mode 100755
index 0000000..7067bd6
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000007.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>save_storable (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 31</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_storable</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+      <span class="ruby-identifier">cache_file</span> = <span class="ruby-identifier">get_cache_filename</span>(<span class="ruby-identifier">filename</span>)
+      <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-identifier">cache_file</span>, <span class="ruby-value str">&quot;w+&quot;</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">f</span><span class="ruby-operator">|</span> <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">dump</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">f</span>) }
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000008.html b/docs/api/classes/XmlSimple/Cache.src/M000008.html
new file mode 100755
index 0000000..fed4f38
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000008.html
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>restore_storable (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 41</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">restore_storable</span>(<span class="ruby-identifier">filename</span>)
+      <span class="ruby-identifier">cache_file</span> = <span class="ruby-identifier">get_cache_filename</span>(<span class="ruby-identifier">filename</span>)
+      <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">exist?</span>(<span class="ruby-identifier">cache_file</span>)
+      <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">mtime</span>(<span class="ruby-identifier">cache_file</span>).<span class="ruby-identifier">to_i</span> <span class="ruby-operator">&gt;</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-identifier">mtime</span>(<span class="ruby-identifier">filename</span>).<span class="ruby-identifier">to_i</span>
+      <span class="ruby-identifier">data</span> = <span class="ruby-keyword kw">nil</span>
+      <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-identifier">cache_file</span>) { <span class="ruby-operator">|</span><span class="ruby-identifier">f</span><span class="ruby-operator">|</span> <span class="ruby-identifier">data</span> = <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">load</span>(<span class="ruby-identifier">f</span>) }
+      <span class="ruby-identifier">data</span>
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000009.html b/docs/api/classes/XmlSimple/Cache.src/M000009.html
new file mode 100755
index 0000000..0cd5b22
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000009.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>save_mem_share (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 56</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_mem_share</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+      <span class="ruby-ivar">@mem_share_cache</span>[<span class="ruby-identifier">filename</span>] = [<span class="ruby-constant">Time</span><span class="ruby-operator">::</span><span class="ruby-identifier">now</span>.<span class="ruby-identifier">to_i</span>, <span class="ruby-identifier">data</span>]
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000010.html b/docs/api/classes/XmlSimple/Cache.src/M000010.html
new file mode 100755
index 0000000..e6a2c5e
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000010.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>restore_mem_share (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 67</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">restore_mem_share</span>(<span class="ruby-identifier">filename</span>)
+      <span class="ruby-identifier">get_from_memory_cache</span>(<span class="ruby-identifier">filename</span>, <span class="ruby-ivar">@mem_share_cache</span>)
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000011.html b/docs/api/classes/XmlSimple/Cache.src/M000011.html
new file mode 100755
index 0000000..64e35d1
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000011.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>save_mem_copy (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 77</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_mem_copy</span>(<span class="ruby-identifier">data</span>, <span class="ruby-identifier">filename</span>)
+      <span class="ruby-ivar">@mem_share_cache</span>[<span class="ruby-identifier">filename</span>] = [<span class="ruby-constant">Time</span><span class="ruby-operator">::</span><span class="ruby-identifier">now</span>.<span class="ruby-identifier">to_i</span>, <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">dump</span>(<span class="ruby-identifier">data</span>)]
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000012.html b/docs/api/classes/XmlSimple/Cache.src/M000012.html
new file mode 100755
index 0000000..31f0784
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000012.html
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+  <title>restore_mem_copy (XmlSimple::Cache)</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre><span class="ruby-comment cmt"># File lib/xmlsimple.rb, line 87</span>
+    <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">restore_mem_copy</span>(<span class="ruby-identifier">filename</span>)
+      <span class="ruby-identifier">data</span> = <span class="ruby-identifier">get_from_memory_cache</span>(<span class="ruby-identifier">filename</span>, <span class="ruby-ivar">@mem_share_cache</span>)
+      <span class="ruby-identifier">data</span> = <span class="ruby-constant">Marshal</span>.<span class="ruby-identifier">load</span>(<span class="ruby-identifier">data</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">data</span>.<span class="ruby-identifier">nil?</span>
+      <span class="ruby-identifier">data</span>
+    <span class="ruby-keyword kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000031.html b/docs/api/classes/XmlSimple/Cache.src/M000031.html
new file mode 100755
index 0000000..8a14a09
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000031.html
@@ -0,0 +1,16 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>new (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 19</span>
+    <span class="kw">def</span> initialize
+      @mem_share_cache = {}
+      @mem_copy_cache  = {}
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000032.html b/docs/api/classes/XmlSimple/Cache.src/M000032.html
new file mode 100755
index 0000000..6f2d815
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000032.html
@@ -0,0 +1,16 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>save_storable (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 30</span>
+    <span class="kw">def</span> save_storable(data, filename)
+      cache_file = get_cache_filename(filename)
+      File.open(cache_file, <span class="str">&quot;w+&quot;</span>) { |f| Marshal.dump(data, f) }
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000033.html b/docs/api/classes/XmlSimple/Cache.src/M000033.html
new file mode 100755
index 0000000..4c24649
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000033.html
@@ -0,0 +1,20 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>restore_storable (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 40</span>
+    <span class="kw">def</span> restore_storable(filename)
+      cache_file = get_cache_filename(filename)
+      <span class="kw">return</span> <span class="kw">nil</span> <span class="kw">unless</span> File::exist?(cache_file)
+      <span class="kw">return</span> <span class="kw">nil</span> <span class="kw">unless</span> File::mtime(cache_file).to_i &gt; File::mtime(filename).to_i
+      data = <span class="kw">nil</span>
+      File.open(cache_file) { |f| data = Marshal.load(f) }
+      data
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000034.html b/docs/api/classes/XmlSimple/Cache.src/M000034.html
new file mode 100755
index 0000000..01b1d2e
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000034.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>save_mem_share (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 55</span>
+    <span class="kw">def</span> save_mem_share(data, filename)
+      @mem_share_cache[filename] = [Time::now.to_i, data]
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000035.html b/docs/api/classes/XmlSimple/Cache.src/M000035.html
new file mode 100755
index 0000000..24f880f
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000035.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>restore_mem_share (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 66</span>
+    <span class="kw">def</span> restore_mem_share(filename)
+      get_from_memory_cache(filename, @mem_share_cache)
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000036.html b/docs/api/classes/XmlSimple/Cache.src/M000036.html
new file mode 100755
index 0000000..702e5a6
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000036.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>save_mem_copy (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 76</span>
+    <span class="kw">def</span> save_mem_copy(data, filename)
+      @mem_share_cache[filename] = [Time::now.to_i, Marshal.dump(data)]
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000037.html b/docs/api/classes/XmlSimple/Cache.src/M000037.html
new file mode 100755
index 0000000..4271411
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000037.html
@@ -0,0 +1,17 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>restore_mem_copy (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 86</span>
+    <span class="kw">def</span> restore_mem_copy(filename)
+      data = get_from_memory_cache(filename, @mem_share_cache)
+      data = Marshal.load(data) <span class="kw">unless</span> data.nil?
+      data
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000038.html b/docs/api/classes/XmlSimple/Cache.src/M000038.html
new file mode 100755
index 0000000..fd4d928
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000038.html
@@ -0,0 +1,15 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>get_cache_filename (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 101</span>
+    <span class="kw">def</span> get_cache_filename(filename)
+      filename.sub(<span class="re">/(\.xml)?$/</span>, <span class="str">'.stor'</span>)
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/classes/XmlSimple/Cache.src/M000039.html b/docs/api/classes/XmlSimple/Cache.src/M000039.html
new file mode 100755
index 0000000..04ea923
--- /dev/null
+++ b/docs/api/classes/XmlSimple/Cache.src/M000039.html
@@ -0,0 +1,17 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>get_from_memory_cache (XmlSimple::Cache)</title>
+<link rel=StyleSheet href="../../.././rdoc-style.css" type="text/css" media="screen" />
+</head>
+<body bgcolor="white">
+<pre><span class="cmt"># File lib/xmlsimple.rb, line 113</span>
+    <span class="kw">def</span> get_from_memory_cache(filename, cache)
+      <span class="kw">return</span> <span class="kw">nil</span> <span class="kw">unless</span> cache[filename]
+      <span class="kw">return</span> <span class="kw">nil</span> <span class="kw">unless</span> cache[filename][0] &gt; File::mtime(filename).to_i
+      <span class="kw">return</span> cache[filename][1]
+    <span class="kw">end</span></pre>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/created.rid b/docs/api/created.rid
new file mode 100755
index 0000000..cf75005
--- /dev/null
+++ b/docs/api/created.rid
@@ -0,0 +1,2 @@
+Wed, 19 Jan 2011 20:24:21 +0100
+lib/xmlsimple.rb	Wed, 19 Jan 2011 20:23:13 +0100
diff --git a/docs/api/files/lib/xmlsimple_rb.html b/docs/api/files/lib/xmlsimple_rb.html
new file mode 100755
index 0000000..3b55984
--- /dev/null
+++ b/docs/api/files/lib/xmlsimple_rb.html
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>File: xmlsimple.rb</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <meta http-equiv="Content-Script-Type" content="text/javascript" />
+  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
+  <script type="text/javascript">
+  // <![CDATA[
+
+  function popupCode( url ) {
+    window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+  }
+
+  function toggleCode( id ) {
+    if ( document.getElementById )
+      elem = document.getElementById( id );
+    else if ( document.all )
+      elem = eval( "document.all." + id );
+    else
+      return false;
+
+    elemStyle = elem.style;
+    
+    if ( elemStyle.display != "block" ) {
+      elemStyle.display = "block"
+    } else {
+      elemStyle.display = "none"
+    }
+
+    return true;
+  }
+  
+  // Make codeblocks hidden by default
+  document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
+  
+  // ]]>
+  </script>
+
+</head>
+<body>
+
+
+
+  <div id="fileHeader">
+    <h1>xmlsimple.rb</h1>
+    <table class="header-table">
+    <tr class="top-aligned-row">
+      <td><strong>Path:</strong></td>
+      <td>lib/xmlsimple.rb
+      </td>
+    </tr>
+    <tr class="top-aligned-row">
+      <td><strong>Last Update:</strong></td>
+      <td>Mon Mar 12 17:59:04 +0100 2007</td>
+    </tr>
+    </table>
+  </div>
+  <!-- banner header -->
+
+  <div id="bodyContent">
+
+
+
+  <div id="contextContent">
+
+    <div id="description">
+      <h1><a href="../../classes/XmlSimple.html">XmlSimple</a></h1>
+<table>
+<tr><td valign="top">Author:</td><td>Maik Schmidt &lt;contact@maik-schmidt.de&gt;
+
+</td></tr>
+<tr><td valign="top">Copyright:</td><td>Copyright (c) 2003-2006 Maik Schmidt
+
+</td></tr>
+<tr><td valign="top">License:</td><td>Distributes under the same terms as Ruby.
+
+</td></tr>
+</table>
+
+    </div>
+
+    <div id="requires-list">
+      <h3 class="section-bar">Required files</h3>
+
+      <div class="name-list">
+      rexml/document&nbsp;&nbsp;
+      stringio&nbsp;&nbsp;
+      </div>
+    </div>
+
+   </div>
+
+
+  </div>
+
+
+    <!-- if includes -->
+
+    <div id="section">
+
+
+
+
+
+      
+
+
+    <!-- if method_list -->
+
+
+  </div>
+
+
+<div id="validator-badges">
+  <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/fr_class_index.html b/docs/api/fr_class_index.html
new file mode 100755
index 0000000..51ee078
--- /dev/null
+++ b/docs/api/fr_class_index.html
@@ -0,0 +1,28 @@
+
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<!--
+
+    Classes
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>Classes</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
+  <base target="docwin" />
+</head>
+<body>
+<div id="index">
+  <h1 class="section-bar">Classes</h1>
+  <div id="index-entries">
+    <a href="classes/XmlSimple.html">XmlSimple</a><br />
+    <a href="classes/XmlSimple/Cache.html">XmlSimple::Cache</a><br />
+  </div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/fr_file_index.html b/docs/api/fr_file_index.html
new file mode 100755
index 0000000..6d2ca48
--- /dev/null
+++ b/docs/api/fr_file_index.html
@@ -0,0 +1,27 @@
+
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<!--
+
+    Files
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>Files</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
+  <base target="docwin" />
+</head>
+<body>
+<div id="index">
+  <h1 class="section-bar">Files</h1>
+  <div id="index-entries">
+    <a href="files/lib/xmlsimple_rb.html">lib/xmlsimple.rb</a><br />
+  </div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/fr_method_index.html b/docs/api/fr_method_index.html
new file mode 100755
index 0000000..458ec56
--- /dev/null
+++ b/docs/api/fr_method_index.html
@@ -0,0 +1,38 @@
+
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<!--
+
+    Methods
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>Methods</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
+  <base target="docwin" />
+</head>
+<body>
+<div id="index">
+  <h1 class="section-bar">Methods</h1>
+  <div id="index-entries">
+    <a href="classes/XmlSimple.html#M000001">new (XmlSimple)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000006">new (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000012">restore_mem_copy (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000010">restore_mem_share (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000008">restore_storable (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000011">save_mem_copy (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000009">save_mem_share (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple/Cache.html#M000007">save_storable (XmlSimple::Cache)</a><br />
+    <a href="classes/XmlSimple.html#M000002">xml_in (XmlSimple)</a><br />
+    <a href="classes/XmlSimple.html#M000003">xml_in (XmlSimple)</a><br />
+    <a href="classes/XmlSimple.html#M000005">xml_out (XmlSimple)</a><br />
+    <a href="classes/XmlSimple.html#M000004">xml_out (XmlSimple)</a><br />
+  </div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/api/images/brick.png b/docs/api/images/brick.png
new file mode 100755
index 0000000..7851cf3
Binary files /dev/null and b/docs/api/images/brick.png differ
diff --git a/docs/api/images/brick_link.png b/docs/api/images/brick_link.png
new file mode 100755
index 0000000..9ebf013
Binary files /dev/null and b/docs/api/images/brick_link.png differ
diff --git a/docs/api/images/bug.png b/docs/api/images/bug.png
new file mode 100644
index 0000000..2d5fb90
Binary files /dev/null and b/docs/api/images/bug.png differ
diff --git a/docs/api/images/bullet_black.png b/docs/api/images/bullet_black.png
new file mode 100755
index 0000000..5761970
Binary files /dev/null and b/docs/api/images/bullet_black.png differ
diff --git a/docs/api/images/bullet_toggle_minus.png b/docs/api/images/bullet_toggle_minus.png
new file mode 100755
index 0000000..b47ce55
Binary files /dev/null and b/docs/api/images/bullet_toggle_minus.png differ
diff --git a/docs/api/images/bullet_toggle_plus.png b/docs/api/images/bullet_toggle_plus.png
new file mode 100755
index 0000000..9ab4a89
Binary files /dev/null and b/docs/api/images/bullet_toggle_plus.png differ
diff --git a/docs/api/images/date.png b/docs/api/images/date.png
new file mode 100755
index 0000000..783c833
Binary files /dev/null and b/docs/api/images/date.png differ
diff --git a/docs/api/images/find.png b/docs/api/images/find.png
new file mode 100755
index 0000000..1547479
Binary files /dev/null and b/docs/api/images/find.png differ
diff --git a/docs/api/images/loadingAnimation.gif b/docs/api/images/loadingAnimation.gif
new file mode 100644
index 0000000..82290f4
Binary files /dev/null and b/docs/api/images/loadingAnimation.gif differ
diff --git a/docs/api/images/macFFBgHack.png b/docs/api/images/macFFBgHack.png
new file mode 100644
index 0000000..c6473b3
Binary files /dev/null and b/docs/api/images/macFFBgHack.png differ
diff --git a/docs/api/images/package.png b/docs/api/images/package.png
new file mode 100755
index 0000000..da3c2a2
Binary files /dev/null and b/docs/api/images/package.png differ
diff --git a/docs/api/images/page_green.png b/docs/api/images/page_green.png
new file mode 100755
index 0000000..de8e003
Binary files /dev/null and b/docs/api/images/page_green.png differ
diff --git a/docs/api/images/page_white_text.png b/docs/api/images/page_white_text.png
new file mode 100755
index 0000000..813f712
Binary files /dev/null and b/docs/api/images/page_white_text.png differ
diff --git a/docs/api/images/page_white_width.png b/docs/api/images/page_white_width.png
new file mode 100755
index 0000000..1eb8809
Binary files /dev/null and b/docs/api/images/page_white_width.png differ
diff --git a/docs/api/images/plugin.png b/docs/api/images/plugin.png
new file mode 100755
index 0000000..6187b15
Binary files /dev/null and b/docs/api/images/plugin.png differ
diff --git a/docs/api/images/ruby.png b/docs/api/images/ruby.png
new file mode 100755
index 0000000..f763a16
Binary files /dev/null and b/docs/api/images/ruby.png differ
diff --git a/docs/api/images/tag_green.png b/docs/api/images/tag_green.png
new file mode 100755
index 0000000..83ec984
Binary files /dev/null and b/docs/api/images/tag_green.png differ
diff --git a/docs/api/images/wrench.png b/docs/api/images/wrench.png
new file mode 100755
index 0000000..5c8213f
Binary files /dev/null and b/docs/api/images/wrench.png differ
diff --git a/docs/api/images/wrench_orange.png b/docs/api/images/wrench_orange.png
new file mode 100755
index 0000000..565a933
Binary files /dev/null and b/docs/api/images/wrench_orange.png differ
diff --git a/docs/api/images/zoom.png b/docs/api/images/zoom.png
new file mode 100755
index 0000000..908612e
Binary files /dev/null and b/docs/api/images/zoom.png differ
diff --git a/docs/api/index.html b/docs/api/index.html
new file mode 100755
index 0000000..a6a9ab3
--- /dev/null
+++ b/docs/api/index.html
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+	"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+	<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+
+	<title>RDoc Documentation</title>
+
+	<link type="text/css" media="screen" href="rdoc.css" rel="stylesheet" />
+
+	<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
+	<script src="js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
+	<script src="js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
+	<script src="js/darkfish.js" type="text/javascript" charset="utf-8"></script>
+
+</head>
+<body class="indexpage">
+
+	
+	<h1>RDoc Documentation</h1>
+
+	
+	<p>This is the API documentation for 'RDoc Documentation'.</p>
+	
+
+	
+	
+
+	<h2 id="classes">Classes/Modules</h2>
+	<ul>
+		
+		<li class="class"><a href="XmlSimple.html">XmlSimple</a></li>
+		
+		<li class="class"><a href="XmlSimple/Cache.html">XmlSimple::Cache</a></li>
+		
+	</ul>
+
+	<h2 id="methods">Methods</h2>
+	<ul>
+		
+			<li><a href="XmlSimple.html#method-c-new">::new &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-c-new">::new &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple.html#method-c-xml_in">::xml_in &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-c-xml_out">::xml_out &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-collapse">#collapse &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-collapse_content">#collapse_content &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-collapse_text_node">#collapse_text_node &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-empty">#empty &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-escape_value">#escape_value &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-find_xml_file">#find_xml_file &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-fold_array">#fold_array &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-fold_array_by_name">#fold_array_by_name &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-fold_arrays">#fold_arrays &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-force_array%3F">#force_array? &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-get_attributes">#get_attributes &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-get_cache_filename">#get_cache_filename &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-get_from_memory_cache">#get_from_memory_cache &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-get_var">#get_var &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-handle_options">#handle_options &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-has_mixed_content%3F">#has_mixed_content? &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-hash_to_array">#hash_to_array &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-load_xml_file">#load_xml_file &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-merge">#merge &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-node_to_text">#node_to_text &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-normalise_space">#normalise_space &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-normalize_option_names">#normalize_option_names &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-parse">#parse &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-put_into_cache">#put_into_cache &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-restore_mem_copy">#restore_mem_copy &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-restore_mem_share">#restore_mem_share &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-restore_storable">#restore_storable &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-save_mem_copy">#save_mem_copy &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-save_mem_share">#save_mem_share &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple/Cache.html#method-i-save_storable">#save_storable &mdash; XmlSimple::Cache</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-scalar">#scalar &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-set_var">#set_var &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-value_to_xml">#value_to_xml &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-xml_in">#xml_in &mdash; XmlSimple</a></li>
+		
+			<li><a href="XmlSimple.html#method-i-xml_out">#xml_out &mdash; XmlSimple</a></li>
+		
+	</ul>
+
+	<div id="validator-badges">
+		<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+		<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
+			Rdoc Generator</a> 1.1.6</small>.</p>
+	</div>
+</body>
+</html>
diff --git a/docs/api/js/darkfish.js b/docs/api/js/darkfish.js
new file mode 100644
index 0000000..43528fd
--- /dev/null
+++ b/docs/api/js/darkfish.js
@@ -0,0 +1,116 @@
+/**
+ * 
+ * Darkfish Page Functions
+ * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
+ * 
+ * Author: Michael Granger <mgranger@laika.com>
+ * 
+ */
+
+/* Provide console simulation for firebug-less environments */
+if (!("console" in window) || !("firebug" in console)) {
+    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+
+    window.console = {};
+    for (var i = 0; i < names.length; ++i)
+        window.console[names[i]] = function() {};
+};
+
+
+/**
+ * Unwrap the first element that matches the given @expr@ from the targets and return them.
+ */
+$.fn.unwrap = function( expr ) {
+  return this.each( function() {
+     $(this).parents( expr ).eq( 0 ).after( this ).remove();
+  });
+};
+
+
+function showSource( e ) {
+	var target = e.target;
+	var codeSections = $(target).
+		parents('.method-detail').
+		find('.method-source-code');
+
+	$(target).
+		parents('.method-detail').
+		find('.method-source-code').
+		slideToggle();
+};
+
+function hookSourceViews() {
+	$('.method-description,.method-heading').click( showSource );
+};
+
+function toggleDebuggingSection() {
+	$('.debugging-section').slideToggle();
+};
+
+function hookDebuggingToggle() {
+	$('#debugging-toggle img').click( toggleDebuggingSection );
+};
+
+function hookQuickSearch() {
+	$('.quicksearch-field').each( function() {
+		var searchElems = $(this).parents('.section').find( 'li' );
+		var toggle = $(this).parents('.section').find('h3 .search-toggle');
+		// console.debug( "Toggle is: %o", toggle );
+		var qsbox = $(this).parents('form').get( 0 );
+		
+		$(this).quicksearch( this, searchElems, {
+			noSearchResultsIndicator: 'no-class-search-results',
+			focusOnLoad: false
+		});
+		$(toggle).click( function() {
+			// console.debug( "Toggling qsbox: %o", qsbox );
+			$(qsbox).toggle();
+		});
+	});
+};
+
+function highlightTarget( anchor ) {
+	console.debug( "Highlighting target '%s'.", anchor );
+
+	$("a[name=" + anchor + "]").each( function() {
+		if ( !$(this).parent().parent().hasClass('target-section') ) {
+			console.debug( "Wrapping the target-section" );
+			$('div.method-detail').unwrap( 'div.target-section' );
+			$(this).parent().wrap( '<div class="target-section"></div>' );
+		} else {
+			console.debug( "Already wrapped." );
+		}
+	});
+};
+
+function highlightLocationTarget() {
+	console.debug( "Location hash: %s", window.location.hash );
+	if ( ! window.location.hash || window.location.hash.length == 0 ) return;
+	
+	var anchor = window.location.hash.substring(1);
+	console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" );
+
+	highlightTarget( anchor );
+};
+
+function highlightClickTarget( event ) {
+	console.debug( "Highlighting click target for event %o", event.target );
+	try {
+		var anchor = $(event.target).attr( 'href' ).substring(1);
+		console.debug( "Found target anchor: %s", anchor );
+		highlightTarget( anchor );
+	} catch ( err ) {
+		console.error( "Exception while highlighting: %o", err );
+	};
+};
+
+
+$(document).ready( function() {
+	hookSourceViews();
+	hookDebuggingToggle();
+	hookQuickSearch();
+	highlightLocationTarget();
+
+	$('ul.link-list a').bind( "click", highlightClickTarget );
+});
diff --git a/docs/api/js/jquery.js b/docs/api/js/jquery.js
new file mode 100644
index 0000000..afe9e74
--- /dev/null
+++ b/docs/api/js/jquery.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-09-25 09:50:52 -0700 (Thu, 25 Sep 2008) $
+ * $Rev: 38 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
\ No newline at end of file
diff --git a/docs/api/js/quicksearch.js b/docs/api/js/quicksearch.js
new file mode 100644
index 0000000..332772a
--- /dev/null
+++ b/docs/api/js/quicksearch.js
@@ -0,0 +1,114 @@
+/**
+ * 
+ * JQuery QuickSearch - Hook up a form field to hide non-matching elements.
+ * $Id: quicksearch.js 53 2009-01-07 02:52:03Z deveiant $
+ * 
+ * Author: Michael Granger <mgranger@laika.com>
+ * 
+ */
+jQuery.fn.quicksearch = function( target, searchElems, options ) {
+	// console.debug( "Quicksearch fn" );
+
+	var settings = {
+		delay: 250,
+		clearButton: false,
+		highlightMatches: false,
+		focusOnLoad: false,
+		noSearchResultsIndicator: null
+	};
+	if ( options ) $.extend( settings, options );
+	
+	return jQuery(this).each( function() {
+		// console.debug( "Creating a new quicksearch on %o for %o", this, searchElems );
+		new jQuery.quicksearch( this, searchElems, settings );
+	});
+};
+
+
+jQuery.quicksearch = function( searchBox, searchElems, settings ) {
+	var timeout;
+	var boxdiv = $(searchBox).parents('div').eq(0);
+
+	function init() {
+		setupKeyEventHandlers();
+		focusOnLoad();
+	};
+
+	function setupKeyEventHandlers() {
+		// console.debug( "Hooking up the 'keypress' event to %o", searchBox );
+		$(searchBox).
+			unbind( 'keyup' ).
+			keyup( function(e) { return onSearchKey( e.keyCode ); });
+		$(searchBox).
+			unbind( 'keypress' ).
+			keypress( function(e) {
+				switch( e.which ) {
+					// Execute the search on Enter, Tab, or Newline
+					case 9:
+					case 13:
+					case 10:
+						clearTimeout( timeout );
+						e.preventDefault();
+						doQuickSearch();
+						break;
+
+					// Allow backspace
+					case 8:
+						return true;
+						break;
+					
+					// Only allow valid search characters
+					default:
+						return validQSChar( e.charCode );
+				}
+			});
+	};
+
+	function focusOnLoad() {
+		if ( !settings.focusOnLoad ) return false;
+		$(searchBox).focus();
+	};
+
+	function onSearchKey ( code ) {
+		clearTimeout( timeout );
+		// console.debug( "...scheduling search." );
+		timeout = setTimeout( doQuickSearch, settings.delay );
+	};
+
+	function validQSChar( code ) {
+		var c = String.fromCharCode( code );
+		return (
+			(c == ':') ||
+			(c >= 'a' && c <= 'z') ||
+			(c >= 'A' && c <= 'Z')
+		  );
+	};
+
+	function doQuickSearch() {
+		var searchText = searchBox.value;
+		var pat = new RegExp( searchText, "im" );
+		var shownCount = 0;
+	
+		if ( settings.noSearchResultsIndicator ) {
+			$('#' + settings.noSearchResultsIndicator).hide();
+		}
+
+		// All elements start out hidden
+		$(searchElems).each( function(index) {
+			var str = $(this).text();
+			
+			if ( pat.test(str) ) {
+				shownCount += 1;
+				$(this).fadeIn();
+			} else {
+				$(this).hide();
+			}
+		});
+
+		if ( shownCount == 0 && settings.noSearchResultsIndicator ) {
+			$('#' + settings.noSearchResultsIndicator).slideDown();
+		}
+	};
+
+	init();
+};
diff --git a/docs/api/js/thickbox-compressed.js b/docs/api/js/thickbox-compressed.js
new file mode 100644
index 0000000..3a3fdae
--- /dev/null
+++ b/docs/api/js/thickbox-compressed.js
@@ -0,0 +1,10 @@
+/*
+ * Thickbox 3 - One Box To Rule Them All.
+ * By Cody Lindley (http://www.codylindley.com)
+ * Copyright (c) 2007 cody lindley
+ * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+var tb_pathToImage = "../images/loadingAnimation.gif";
+
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(o).2S(9(){1u(\'a.18, 3n.18, 3i.18\');1w=1p 1t();1w.L=2H});9 1u(b){$(b).s(9(){6 t=X.Q||X.1v||M;6 a=X.u||X.23;6 g=X.1N||P;19(t,a,g);X.2E();H P})}9 19(d,f,g){3m{3(2t o.v.J.2i==="2g"){$("v","11").r({A:"28%",z:"28%"});$("11").r("22","2Z");3(o.1Y("1F")===M){$("v").q("<U 5=\'1F\'></U><4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}n{3(o.1Y("B")===M){$("v").q("<4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}3(1K()){$("#B").1J("2B")}n{$("#B").1J("2z")}3(d===M){d=""}$("v").q("<4 5=\'K\'><1I L=\'"+1w.L+"\' /></4>");$(\'#K\').2y();6 h;3(f.O("?")!==-1){h=f.3l(0,f.O("?"))}n{h=f}6 i=/\\.2s$|\\.2q$|\\.2m$|\\.2l$|\\.2k$/;6 j=h.1C().2h(i);3(j==\'.2s\'||j==\'.2q\'||j==\'.2m\'||j==\'.2l\'||j==\'.2k\'){1D="";1G="";14="";1z="";1x="";R="";1n="";1r=P;3(g){E=$("a[@1N="+g+"]").36();25(D=0;((D<E.1c)&&(R===""));D++){6 k=E[D].u.1C().2h(i);3(!(E[D].u==f)){3(1r){1z=E[D].Q;1x=E[D].u;R="<1e 5=\'1X\'>&1d;&1d;<a u=\'#\'>2T &2R;</a></1e>"}n{1D=E[D].Q;1G=E[D].u;14="<1e 5=\'1U\'>&1d;&1d;<a u=\'#\'>&2O; 2N</a></1e>"}}n{1r=1b;1n="1t "+(D+1)+" 2L "+(E.1c)}}}S=1p 1t();S.1g=9(){S.1g=M;6 a=2x();6 x=a[0]-1M;6 y=a[1]-1M;6 b=S.z;6 c=S.A;3(b>x){c=c*(x/b);b=x;3(c>y){b=b*(y/c);c=y}}n 3(c>y){b=b*(y/c);c=y;3(b>x){c=c*(x/b);b=x}}13=b+30;1a=c+2G;$("#8").q("<a u=\'\' 5=\'1L\' Q=\'1o\'><1I 5=\'2F\' L=\'"+f+"\' z=\'"+b+"\' A=\'"+c+"\' 23=\'"+d+"\'/></a>"+"<4 5=\'2D\'>"+d+"<4 5=\'2C\'>"+1n+14+R+"</4></4><4 5=\'2A\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4>");$("#Z").s(G);3(!(14==="")){9 12(){3($(o).N("s",12)){$(o).N("s",12)}$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1D,1G,g);H P}$("#1U").s(12)}3(!(R==="")){9 1i(){$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1z,1x,g);H P}$("#1X").s(1i)}o.1h=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}n 3(I==3k){3(!(R=="")){o.1h="";1i()}}n 3(I==3j){3(!(14=="")){o.1h="";12()}}};16();$("#K").C();$("#1L").s(G);$("#8").r({Y:"T"})};S.L=f}n{6 l=f.2r(/^[^\\?]+\\??/,\'\');6 m=2p(l);13=(m[\'z\']*1)+30||3h;1a=(m[\'A\']*1)+3g||3f;W=13-30;V=1a-3e;3(f.O(\'2j\')!=-1){1E=f.1B(\'3d\');$("#15").C();3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4></4><U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\' > </U>")}n{$("#B").N();$("#8").q("<U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\'> </U>")}}n{3($("#8").r("Y")!="T"){3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\'>1l</a> 1k 1j 1s</4></4><4 5=\'F\' J=\'z:"+W+"p;A:"+V+"p\'></4>")}n{$("#B").N();$("#8").q("<4 5=\'F\' 3c=\'3b\' J=\'z:"+W+"p;A:"+V+"p;\'></4>")}}n{$("#F")[0].J.z=W+"p";$("#F")[0].J.A=V+"p";$("#F")[0].3a=0;$("#1H").11(d)}}$("#Z").s(G);3(f.O(\'37\')!=-1){$("#F").q($(\'#\'+m[\'26\']).1T());$("#8").24(9(){$(\'#\'+m[\'26\']).q($("#F").1T())});16();$("#K").C();$("#8").r({Y:"T"})}n 3(f.O(\'2j\')!=-1){16();3($.1q.35){$("#K").C();$("#8").r({Y:"T"})}}n{$("#F").34(f+="&1y="+(1p 33().32()),9(){16();$("#K").C();1u("#F a.18");$("#8").r({Y:"T"})})}}3(!m[\'1A\']){o.21=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}}}}31(e){}}9 1m(){$("#K").C();$("#8").r({Y:"T"})}9 G(){$("#2Y").N("s");$("#Z").N("s");$("#8").2X("2W",9(){$(\'#8,#B,#1F\').2V("24").N().C()});$("#K").C();3(2t o.v.J.2i=="2g"){$("v","11").r({A:"1Z",z:"1Z"});$("11").r("22","")}o.1h="";o.21="";H P}9 16(){$("#8").r({2U:\'-\'+20((13/2),10)+\'p\',z:13+\'p\'});3(!(1V.1q.2Q&&1V.1q.2P<7)){$("#8").r({38:\'-\'+20((1a/2),10)+\'p\'})}}9 2p(a){6 b={};3(!a){H b}6 c=a.1B(/[;&]/);25(6 i=0;i<c.1c;i++){6 d=c[i].1B(\'=\');3(!d||d.1c!=2){39}6 e=2a(d[0]);6 f=2a(d[1]);f=f.2r(/\\+/g,\' \');b[e]=f}H b}9 2x(){6 a=o.2M;6 w=1S.2o||1R.2o||(a&&a.1Q)||o.v.1Q;6 h=1S.1P||1R.1P||(a&&a.2n)||o.v.2n;1O=[w,h];H 1O}9 1K(){6 a=2K.2J.1C();3(a.O(\'2I\')!=-1&&a.O(\'3o\')!=-1){H 1b}}',62,211,'|||if|div|id|var||TB_window|function||||||||||||||else|document|px|append|css|click||href|body||||width|height|TB_overlay|remove|TB_Counter|TB_TempArray|TB_ajaxContent|tb_remove|return|keycode|style|TB_load|src|null|unbind|indexOf|false|title|TB_NextHTML|imgPreloader|block|iframe|ajaxContentH|ajaxContentW|this|display|TB_closeWindowButton||html|goPrev|TB_WIDTH|TB_PrevHTML|TB_iframeContent|tb_position||thickbox|tb_show|TB_HEIGHT|true|length|nbsp|span|Math|onload|onkeydown|goNext|Esc|or|close|tb_showIframe|TB_imageCount|Close|new|browser|TB_FoundURL|Key|Image|tb_init|name|imgLoader|TB_NextURL|random|TB_NextCaption|modal|split|toLowerCase|TB_PrevCaption|urlNoQuery|TB_HideSelect|TB_PrevURL|TB_ajaxWindowTitle|img|addClass|tb_detectMacXFF|TB_ImageOff|150|rel|arrayPageSize|innerHeight|clientWidth|self|window|children|TB_prev|jQuery|frameborder|TB_next|getElementById|auto|parseInt|onkeyup|overflow|alt|unload|for|inlineId||100||unescape|1000|round|hspace|TB_closeAjaxWindow|TB_title|undefined|match|maxHeight|TB_iframe|bmp|gif|png|clientHeight|innerWidth|tb_parseQuery|jpeg|replace|jpg|typeof|which|keyCode|event|tb_getPageSize|show|TB_overlayBG|TB_closeWindow|TB_overlayMacFFBGHack|TB_secondLine|TB_caption|blur|TB_Image|60|tb_pathToImage|mac|userAgent|navigator|of|documentElement|Prev|lt|version|msie|gt|ready|Next|marginLeft|trigger|fast|fadeOut|TB_imageOff|hidden||catch|getTime|Date|load|safari|get|TB_inline|marginTop|continue|scrollTop|TB_modal|class|TB_|45|440|40|630|input|188|190|substr|try|area|firefox'.split('|'),0,{}))
\ No newline at end of file
diff --git a/docs/api/lib/xmlsimple.rb.html b/docs/api/lib/xmlsimple.rb.html
new file mode 100644
index 0000000..b878411
--- /dev/null
+++ b/docs/api/lib/xmlsimple.rb.html
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+
+	<title>File: xmlsimple.rb [RDoc Documentation]</title>
+
+	<link type="text/css" media="screen" href="../rdoc.css" rel="stylesheet" />
+
+	<script src="../js/jquery.js" type="text/javascript" 
+		charset="utf-8"></script>
+	<script src="../js/thickbox-compressed.js" type="text/javascript" 
+		charset="utf-8"></script>
+	<script src="../js/quicksearch.js" type="text/javascript" 
+		charset="utf-8"></script>
+	<script src="../js/darkfish.js" type="text/javascript" 
+		charset="utf-8"></script>
+</head>
+	
+<body class="file file-popup">
+	<div id="metadata">
+		<dl>
+			<dt class="modified-date">Last Modified</dt>
+			<dd class="modified-date">Wed Feb 11 20:41:27 +0100 2009</dd>
+			
+			
+			<dt class="requires">Requires</dt>
+			<dd class="requires">
+				<ul>
+				
+					<li>rexml/document</li>
+				
+					<li>stringio</li>
+				
+				</ul>
+			</dd>
+			
+			
+			
+		</dl>
+
+		
+		<div class="description">
+			<h2>Description</h2>
+			<h1><a href="../XmlSimple.html">XmlSimple</a></h1>
+<table>
+<tr><td valign="top">Author:</td><td>Maik Schmidt <contact@maik-schmidt.de>
+
+</td></tr>
+<tr><td valign="top">Copyright:</td><td>Copyright &#169; 2003-2009 Maik Schmidt
+
+</td></tr>
+<tr><td valign="top">License:</td><td>Distributes under the same terms as Ruby.
+
+</td></tr>
+</table>
+
+		</div>
+		
+	</div>
+</body>
+</html>
+
diff --git a/docs/api/lib/xmlsimple_rb.html b/docs/api/lib/xmlsimple_rb.html
new file mode 100644
index 0000000..b86653e
--- /dev/null
+++ b/docs/api/lib/xmlsimple_rb.html
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+
+	<title>File: xmlsimple.rb [RDoc Documentation]</title>
+
+	<link type="text/css" media="screen" href="../rdoc.css" rel="stylesheet" />
+
+	<script src="../js/jquery.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="../js/thickbox-compressed.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="../js/quicksearch.js" type="text/javascript"
+		charset="utf-8"></script>
+	<script src="../js/darkfish.js" type="text/javascript"
+		charset="utf-8"></script>
+</head>
+
+<body class="file file-popup">
+	<div id="metadata">
+		<dl>
+			<dt class="modified-date">Last Modified</dt>
+			<dd class="modified-date">2011-01-19 20:23:13 +0100</dd>
+
+			
+			<dt class="requires">Requires</dt>
+			<dd class="requires">
+				<ul>
+				
+					<li>rexml/document</li>
+				
+					<li>stringio</li>
+				
+				</ul>
+			</dd>
+			
+
+			
+		</dl>
+	</div>
+
+	<div id="documentation">
+		
+		<div class="description">
+			<h2>Description</h2>
+			<h1><a href="../XmlSimple.html">XmlSimple</a></h1>
+<table>
+<tr><td valign="top">Author</td><td><p>
+Maik Schmidt <contact@maik-schmidt.de>
+</p>
+</td></tr>
+<tr><td valign="top">Copyright</td><td><p>
+Copyright &#169; 2003-2009 Maik Schmidt
+</p>
+</td></tr>
+<tr><td valign="top">License</td><td><p>
+Distributes under the same terms as Ruby.
+</p>
+</td></tr>
+</table>
+
+		</div>
+		
+	</div>
+</body>
+</html>
+
diff --git a/docs/api/rdoc-style.css b/docs/api/rdoc-style.css
new file mode 100755
index 0000000..44c7b3d
--- /dev/null
+++ b/docs/api/rdoc-style.css
@@ -0,0 +1,208 @@
+
+body {
+    font-family: Verdana,Arial,Helvetica,sans-serif;
+    font-size:   90%;
+    margin: 0;
+    margin-left: 40px;
+    padding: 0;
+    background: white;
+}
+
+h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
+h1 { font-size: 150%; }
+h2,h3,h4 { margin-top: 1em; }
+
+a { background: #eef; color: #039; text-decoration: none; }
+a:hover { background: #039; color: #eef; }
+
+/* Override the base stylesheet's Anchor inside a table cell */
+td > a {
+  background: transparent;
+  color: #039;
+  text-decoration: none;
+}
+
+/* and inside a section title */
+.section-title > a {
+  background: transparent;
+  color: #eee;
+  text-decoration: none;
+}
+
+/* === Structural elements =================================== */
+
+div#index {
+    margin: 0;
+    margin-left: -40px;
+    padding: 0;
+    font-size: 90%;
+}
+
+
+div#index a {
+    margin-left: 0.7em;
+}
+
+div#index .section-bar {
+   margin-left: 0px;
+   padding-left: 0.7em;
+   background: #ccc;
+   font-size: small;
+}
+
+
+div#classHeader, div#fileHeader {
+    width: auto;
+    color: white;
+    padding: 0.5em 1.5em 0.5em 1.5em;
+    margin: 0;
+    margin-left: -40px;
+    border-bottom: 3px solid #006;
+}
+
+div#classHeader a, div#fileHeader a {
+    background: inherit;
+    color: white;
+}
+
+div#classHeader td, div#fileHeader td {
+    background: inherit;
+    color: white;
+}
+
+
+div#fileHeader {
+    background: #057;
+}
+
+div#classHeader {
+    background: #048;
+}
+
+
+.class-name-in-header {
+  font-size:  180%;
+  font-weight: bold;
+}
+
+
+div#bodyContent {
+    padding: 0 1.5em 0 1.5em;
+}
+
+div#description {
+    padding: 0.5em 1.5em;
+    background: #efefef;
+    border: 1px dotted #999;
+}
+
+div#description h1,h2,h3,h4,h5,h6 {
+    color: #125;;
+    background: transparent;
+}
+
+div#validator-badges {
+    text-align: center;
+}
+div#validator-badges img { border: 0; }
+
+div#copyright {
+    color: #333;
+    background: #efefef;
+    font: 0.75em sans-serif;
+    margin-top: 5em;
+    margin-bottom: 0;
+    padding: 0.5em 2em;
+}
+
+
+/* === Classes =================================== */
+
+table.header-table {
+    color: white;
+    font-size: small;
+}
+
+.type-note {
+    font-size: small;
+    color: #DEDEDE;
+}
+
+.xxsection-bar {
+    background: #eee;
+    color: #333;
+    padding: 3px;
+}
+
+.section-bar {
+   color: #333;
+   border-bottom: 1px solid #999;
+    margin-left: -20px;
+}
+
+
+.section-title {
+    background: #79a;
+    color: #eee;
+    padding: 3px;
+    margin-top: 2em;
+    margin-left: -30px;
+    border: 1px solid #999;
+}
+
+.top-aligned-row {  vertical-align: top }
+.bottom-aligned-row { vertical-align: bottom }
+
+/* --- Context section classes ----------------------- */
+
+.context-row { }
+.context-item-name { font-family: monospace; font-weight: bold; color: black; }
+.context-item-value { font-size: small; color: #448; }
+.context-item-desc { color: #333; padding-left: 2em; }
+
+/* --- Method classes -------------------------- */
+.method-detail {
+    background: #efefef;
+    padding: 0;
+    margin-top: 0.5em;
+    margin-bottom: 1em;
+    border: 1px dotted #ccc;
+}
+.method-heading {
+  color: black;
+  background: #ccc;
+  border-bottom: 1px solid #666;
+  padding: 0.2em 0.5em 0 0.5em;
+}
+.method-signature { color: black; background: inherit; }
+.method-name { font-weight: bold; }
+.method-args { font-style: italic; }
+.method-description { padding: 0 0.5em 0 0.5em; }
+
+/* --- Source code sections -------------------- */
+
+a.source-toggle { font-size: 90%; }
+div.method-source-code {
+    background: #262626;
+    color: #ffdead;
+    margin: 1em;
+    padding: 0.5em;
+    border: 1px dashed #999;
+    overflow: hidden;
+}
+
+div.method-source-code pre { color: #ffdead; overflow: hidden; }
+
+/* --- Ruby keyword styles --------------------- */
+
+.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
+
+.ruby-constant  { color: #7fffd4; background: transparent; }
+.ruby-keyword { color: #00ffff; background: transparent; }
+.ruby-ivar    { color: #eedd82; background: transparent; }
+.ruby-operator  { color: #00ffee; background: transparent; }
+.ruby-identifier { color: #ffdead; background: transparent; }
+.ruby-node    { color: #ffa07a; background: transparent; }
+.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
+.ruby-regexp  { color: #ffa07a; background: transparent; }
+.ruby-value   { color: #7fffd4; background: transparent; }
\ No newline at end of file
diff --git a/docs/api/rdoc.css b/docs/api/rdoc.css
new file mode 100644
index 0000000..ffe9960
--- /dev/null
+++ b/docs/api/rdoc.css
@@ -0,0 +1,706 @@
+/*
+ * "Darkfish" Rdoc CSS
+ * $Id: rdoc.css 54 2009-01-27 01:09:48Z deveiant $
+ *
+ * Author: Michael Granger <ged@FaerieMUD.org>
+ *
+ */
+
+/* Base Green is: #6C8C22 */
+
+*{ padding: 0; margin: 0; }
+
+body {
+  background: #efefef;
+	font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif;
+}
+body.class, body.module, body.file {
+    margin-left: 40px;
+}
+body.file-popup {
+	font-size: 90%;
+	margin-left: 0;
+}
+
+h1 {
+	font-size: 300%;
+	text-shadow: rgba(135,145,135,0.65) 2px 2px 3px;
+	color: #6C8C22;
+}
+h2,h3,h4 { margin-top: 1.5em; }
+
+:link,
+:visited {
+	color: #6C8C22;
+	text-decoration: none;
+}
+:link:hover,
+:visited:hover {
+ 	border-bottom: 1px dotted #6C8C22;
+}
+
+pre {
+	background: #ddd;
+	padding: 0.5em 0;
+}
+
+
+/* @group Generic Classes */
+
+.initially-hidden {
+	display: none;
+}
+
+.quicksearch-field {
+	width: 98%;
+	background: #ddd;
+	border: 1px solid #aaa;
+	height: 1.5em;
+	-webkit-border-radius: 4px;
+}
+.quicksearch-field:focus {
+	background: #f1edba;
+}
+
+.missing-docs {
+	font-size: 120%;
+	background: white url(images/wrench_orange.png) no-repeat 4px center;
+	color: #ccc;
+	line-height: 2em;
+	border: 1px solid #d00;
+	opacity: 1;
+	padding-left: 20px;
+	text-indent: 24px;
+	letter-spacing: 3px;
+	font-weight: bold;
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+}
+
+.target-section {
+	border: 2px solid #dcce90;
+	border-left-width: 8px;
+	padding: 0 1em;
+	background: #fff3c2;
+}
+
+/* @end */
+
+
+/* @group Index Page, Standalone file pages */
+body.indexpage {
+	margin: 1em 3em;
+}
+body.indexpage p,
+body.indexpage div,
+body.file p {
+	margin: 1em 0;
+}
+
+.indexpage ul,
+.file #documentation ul {
+	line-height: 160%;
+	list-style: none;
+}
+.indexpage ul :link,
+.indexpage ul :visited {
+	font-size: 16px;
+}
+
+.indexpage li,
+.file #documentation li {
+	padding-left: 20px;
+	background: url(images/bullet_black.png) no-repeat left 4px;
+}
+.indexpage li.module {
+	background: url(images/package.png) no-repeat left 4px;
+}
+.indexpage li.class {
+	background: url(images/ruby.png) no-repeat left 4px;
+}
+.indexpage li.file {
+	background: url(images/page_white_text.png) no-repeat left 4px;
+}
+.file li p,
+.indexpage li p {
+  margin: 0 0;
+}
+
+/* @end */
+
+/* @group Top-Level Structure */
+
+.class #metadata,
+.file #metadata,
+.module #metadata {
+	float: left;
+	width: 260px;
+}
+
+.class #documentation,
+.file #documentation,
+.module #documentation {
+	margin: 2em 1em 5em 300px;
+	min-width: 340px;
+}
+
+.file #metadata {
+	margin: 0.8em;
+}
+
+#validator-badges {
+	clear: both;
+	margin: 1em 1em 2em;
+}
+
+/* @end */
+
+/* @group Metadata Section */
+#metadata .section {
+	background-color: #dedede;
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+	border: 1px solid #aaa;
+	margin: 0 8px 16px;
+	font-size: 90%;
+	overflow: hidden;
+}
+#metadata h3.section-header {
+	margin: 0;
+	padding: 2px 8px;
+	background: #ccc;
+	color: #666;
+	-moz-border-radius-topleft: 4px;
+	-moz-border-radius-topright: 4px;
+	-webkit-border-top-left-radius: 4px;
+	-webkit-border-top-right-radius: 4px;
+	border-bottom: 1px solid #aaa;
+}
+#metadata #home-section h3.section-header {
+  border-bottom: 0;
+}
+
+#metadata ul,
+#metadata dl,
+#metadata p {
+	padding:  8px;
+	list-style: none;
+}
+
+#file-metadata ul {
+	padding-left: 28px;
+	list-style-image: url(images/page_green.png);
+}
+
+dl.svninfo {
+	color: #666;
+	margin: 0;
+}
+dl.svninfo dt {
+	font-weight: bold;
+}
+
+ul.link-list li {
+	white-space: nowrap;
+}
+ul.link-list .type {
+	font-size: 8px;
+	text-transform: uppercase;
+	color: white;
+	background: #969696;
+	padding: 2px 4px;
+	-webkit-border-radius: 5px;
+}
+
+/* @end */
+
+
+/* @group Project Metadata Section */
+#project-metadata {
+	margin-top: 3em;
+}
+
+.file #project-metadata {
+  margin-top: 0em;
+}
+
+#project-metadata .section {
+	border: 1px solid #aaa;
+}
+#project-metadata h3.section-header {
+	border-bottom: 1px solid #aaa;
+	position: relative;
+}
+#project-metadata h3.section-header .search-toggle {
+	position: absolute;
+	right: 5px;
+}
+
+
+#project-metadata form {
+	color: #777;
+	background: #ccc;
+	padding: 8px 8px 16px;
+	border-bottom: 1px solid #bbb;
+}
+#project-metadata fieldset {
+	border: 0;
+}
+
+#no-class-search-results {
+	margin: 0 auto 1em;
+	text-align: center;
+	font-size: 14px;
+	font-weight: bold;
+	color: #aaa;
+}
+
+/* @end */
+
+
+/* @group Documentation Section */
+#description {
+	font-size: 100%;
+	color: #333;
+}
+
+#description p {
+	margin: 1em 0.4em;
+}
+
+#description li p {
+  margin: 0;
+}
+
+#description ul {
+	margin-left: 1.5em;
+}
+#description ul li {
+	line-height: 1.4em;
+}
+
+#description dl,
+#documentation dl {
+	margin: 8px 1.5em;
+	border: 1px solid #ccc;
+}
+#description dl {
+	font-size: 14px;
+}
+
+#description dt,
+#documentation dt {
+	padding: 2px 4px;
+	font-weight: bold;
+	background: #ddd;
+}
+#description dd,
+#documentation dd  {
+	padding: 2px 12px;
+}
+#description dd + dt,
+#documentation dd + dt {
+	margin-top: 0.7em;
+}
+
+#documentation .section {
+	font-size: 90%;
+}
+#documentation h3.section-header {
+	margin-top: 2em;
+	padding: 0.75em 0.5em;
+	background-color: #dedede;
+	color: #333;
+	font-size: 150%;
+	border: 1px solid #bbb;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+}
+
+#constants-list > dl,
+#attributes-list > dl {
+	margin: 1em 0 2em;
+	border: 0;
+}
+#constants-list > dl dt,
+#attributes-list > dl dt {
+	padding-left: 0;
+	font-weight: bold;
+	font-family: Monaco, "Andale Mono";
+	background: inherit;
+}
+#constants-list > dl dt a,
+#attributes-list > dl dt a {
+	color: inherit;
+}
+#constants-list > dl dd,
+#attributes-list > dl dd {
+	margin: 0 0 1em 0;
+	padding: 0;
+	color: #666;
+}
+
+/* @group Method Details */
+
+#documentation .method-source-code {
+	display: none;
+}
+
+#documentation .method-detail {
+	margin: 0.5em 0;
+	padding: 0.5em 0;
+	cursor: pointer;
+}
+#documentation .method-detail:hover {
+	background-color: #f1edba;
+}
+#documentation .method-heading {
+	position: relative;
+	padding: 2px 4px 0 20px;
+	font-size: 125%;
+	font-weight: bold;
+	color: #333;
+	background: url(images/brick.png) no-repeat left bottom;
+}
+#documentation .method-heading :link,
+#documentation .method-heading :visited {
+	color: inherit;
+}
+#documentation .method-click-advice {
+	position: absolute;
+	top: 2px;
+	right: 5px;
+	font-size: 10px;
+	color: #9b9877;
+	visibility: hidden;
+	padding-right: 20px;
+	line-height: 20px;
+	background: url(images/zoom.png) no-repeat right top;
+}
+#documentation .method-detail:hover .method-click-advice {
+	visibility: visible;
+}
+
+#documentation .method-alias .method-heading {
+	color: #666;
+	background: url(images/brick_link.png) no-repeat left bottom;
+}
+
+#documentation .method-description,
+#documentation .aliases {
+	margin: 0 20px;
+	line-height: 1.2em;
+	color: #666;
+}
+#documentation .aliases {
+	padding-top: 4px;
+	font-style: italic;
+	cursor: default;
+}
+#documentation .method-description p {
+	padding: 0;
+}
+#documentation .method-description p + p {
+	margin-bottom: 0.5em;
+}
+#documentation .method-description ul {
+  margin-left: 1.5em;
+}
+
+#documentation .attribute-method-heading {
+	background: url(images/tag_green.png) no-repeat left bottom;
+}
+#documentation #attribute-method-details .method-detail:hover {
+	background-color: transparent;
+	cursor: default;
+}
+#documentation .attribute-access-type {
+	font-size: 60%;
+	text-transform: uppercase;
+	vertical-align: super;
+	padding: 0 2px;
+}
+/* @end */
+
+/* @end */
+
+
+
+/* @group Source Code */
+
+div.method-source-code {
+    background: #262626;
+    color: #efefef;
+    margin: 1em;
+    padding: 0.5em;
+    border: 1px dashed #999;
+    overflow: hidden;
+}
+
+div.method-source-code pre {
+	background: inherit;
+	padding: 0;
+	color: white;
+	overflow: auto;
+}
+
+/* @group Ruby keyword styles */
+
+.ruby-constant   { color: #7fffd4; background: transparent; }
+.ruby-keyword    { color: #00ffff; background: transparent; }
+.ruby-ivar       { color: #eedd82; background: transparent; }
+.ruby-operator   { color: #00ffee; background: transparent; }
+.ruby-identifier { color: #ffdead; background: transparent; }
+.ruby-node       { color: #ffa07a; background: transparent; }
+.ruby-comment    { color: #b22222; font-weight: bold; background: transparent; }
+.ruby-regexp     { color: #ffa07a; background: transparent; }
+.ruby-value      { color: #7fffd4; background: transparent; }
+
+/* @end */
+/* @end */
+
+
+/* @group File Popup Contents */
+
+.file #metadata,
+.file-popup #metadata {
+}
+
+.file-popup dl {
+	font-size: 80%;
+	padding: 0.75em;
+	background-color: #dedede;
+	color: #333;
+	border: 1px solid #bbb;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+}
+.file dt {
+	font-weight: bold;
+	padding-left: 22px;
+	line-height: 20px;
+	background: url(images/page_white_width.png) no-repeat left top;
+}
+.file dt.modified-date {
+	background: url(images/date.png) no-repeat left top;
+}
+.file dt.requires {
+	background: url(images/plugin.png) no-repeat left top;
+}
+.file dt.scs-url {
+	background: url(images/wrench.png) no-repeat left top;
+}
+
+.file dl dd {
+	margin: 0 0 1em 0;
+}
+.file #metadata dl dd ul {
+	list-style: circle;
+	margin-left: 20px;
+	padding-top: 0;
+}
+.file #metadata dl dd ul li {
+}
+
+
+.file h2 {
+	margin-top: 2em;
+	padding: 0.75em 0.5em;
+	background-color: #dedede;
+	color: #333;
+	font-size: 120%;
+	border: 1px solid #bbb;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+}
+
+/* @end */
+
+
+
+
+/* @group ThickBox Styles */
+#TB_window {
+	font: 12px Arial, Helvetica, sans-serif;
+	color: #333333;
+}
+
+#TB_secondLine {
+	font: 10px Arial, Helvetica, sans-serif;
+	color:#666666;
+}
+
+#TB_window :link,
+#TB_window :visited        { color: #666666; }
+#TB_window :link:hover,
+#TB_window :visited:hover  { color: #000;    }
+#TB_window :link:active,
+#TB_window :visited:active { color: #666666; }
+#TB_window :link:focus,
+#TB_window :visited:focus  { color: #666666; }
+
+#TB_overlay {
+	position: fixed;
+	z-index:100;
+	top: 0px;
+	left: 0px;
+	height:100%;
+	width:100%;
+}
+
+.TB_overlayMacFFBGHack {background: url(images/macFFBgHack.png) repeat;}
+.TB_overlayBG {
+	background-color:#000;
+	filter:alpha(opacity=75);
+	-moz-opacity: 0.75;
+	opacity: 0.75;
+}
+
+* html #TB_overlay { /* ie6 hack */
+     position: absolute;
+     height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_window {
+	position: fixed;
+	background: #ffffff;
+	z-index: 102;
+	color:#000000;
+	display:none;
+	border: 4px solid #525252;
+	text-align:left;
+	top:50%;
+	left:50%;
+}
+
+* html #TB_window { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_window img#TB_Image {
+	display:block;
+	margin: 15px 0 0 15px;
+	border-right: 1px solid #ccc;
+	border-bottom: 1px solid #ccc;
+	border-top: 1px solid #666;
+	border-left: 1px solid #666;
+}
+
+#TB_caption{
+	height:25px;
+	padding:7px 30px 10px 25px;
+	float:left;
+}
+
+#TB_closeWindow{
+	height:25px;
+	padding:11px 25px 10px 0;
+	float:right;
+}
+
+#TB_closeAjaxWindow{
+	padding:7px 10px 5px 0;
+	margin-bottom:1px;
+	text-align:right;
+	float:right;
+}
+
+#TB_ajaxWindowTitle{
+	float:left;
+	padding:7px 0 5px 10px;
+	margin-bottom:1px;
+	font-size: 22px;
+}
+
+#TB_title{
+	background-color: #6C8C22;
+	color: #dedede;
+	height:40px;
+}
+#TB_title :link,
+#TB_title :visited {
+	color: white !important;
+	border-bottom: 1px dotted #dedede;
+}
+
+#TB_ajaxContent{
+	clear:both;
+	padding:2px 15px 15px 15px;
+	overflow:auto;
+	text-align:left;
+	line-height:1.4em;
+}
+
+#TB_ajaxContent.TB_modal{
+	padding:15px;
+}
+
+#TB_ajaxContent p{
+	padding:5px 0px 5px 0px;
+}
+
+#TB_load{
+	position: fixed;
+	display:none;
+	height:13px;
+	width:208px;
+	z-index:103;
+	top: 50%;
+	left: 50%;
+	margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
+}
+
+* html #TB_load { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_HideSelect{
+	z-index:99;
+	position:fixed;
+	top: 0;
+	left: 0;
+	background-color:#fff;
+	border:none;
+	filter:alpha(opacity=0);
+	-moz-opacity: 0;
+	opacity: 0;
+	height:100%;
+	width:100%;
+}
+
+* html #TB_HideSelect { /* ie6 hack */
+     position: absolute;
+     height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_iframeContent{
+	clear:both;
+	border:none;
+	margin-bottom:-1px;
+	margin-top:1px;
+	_margin-bottom:1px;
+}
+
+/* @end */
+
+/* @group Debugging Section */
+
+#debugging-toggle {
+	text-align: center;
+}
+#debugging-toggle img {
+	cursor: pointer;
+}
+
+#rdoc-debugging-section-dump {
+	display: none;
+	margin: 0 2em 2em;
+	background: #ccc;
+	border: 1px solid #999;
+}
+
+
+
+/* @end */
diff --git a/rakefile.rb b/rakefile.rb
new file mode 100755
index 0000000..dd561cb
--- /dev/null
+++ b/rakefile.rb
@@ -0,0 +1,7 @@
+require 'rake/testtask'
+
+Rake::TestTask.new do |t|
+  t.libs << './lib'
+  t.test_files = FileList['test/*.rb']
+  t.verbose = true
+end
diff --git a/test/files/1_xml_in.xml b/test/files/1_xml_in.xml
new file mode 100755
index 0000000..ec26ff2
--- /dev/null
+++ b/test/files/1_xml_in.xml
@@ -0,0 +1,2 @@
+<opt location="files/1_xml_in.xml" />
+
diff --git a/test/files/att.xml b/test/files/att.xml
new file mode 100755
index 0000000..c483b96
--- /dev/null
+++ b/test/files/att.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<atts>
+  <x a="1" b="2">Hello</x>
+  <y c="5">World</y>
+  <z>
+    <inner>Inner</inner>
+  </z>
+</atts>
+
diff --git a/test/files/conversions.xml b/test/files/conversions.xml
new file mode 100644
index 0000000..10c698c
--- /dev/null
+++ b/test/files/conversions.xml
@@ -0,0 +1,5 @@
+<result>
+  <status>OK</status>
+  <total>10</total>
+  <failed>2</failed>
+</result>
\ No newline at end of file
diff --git a/test/files/curtis.xml b/test/files/curtis.xml
new file mode 100755
index 0000000..202f0e8
--- /dev/null
+++ b/test/files/curtis.xml
@@ -0,0 +1,12 @@
+<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug">
+    <server name="sahara" osname="solaris" osversion="2.6">
+      <address>10.0.0.101</address>
+      <address>10.0.1.101</address>
+    </server>
+    <server name="gobi" osname="irix" osversion="6.5"/>
+    <server name="kalahari" osname="linux" osversion="2.0.34">
+      <address>10.0.0.103</address>
+      <address>10.0.1.103</address>
+    </server>
+</config>
+
diff --git a/test/files/desertnet.src b/test/files/desertnet.src
new file mode 100755
index 0000000..7815666
--- /dev/null
+++ b/test/files/desertnet.src
@@ -0,0 +1,13 @@
+<config>
+  <server name="sahara" osname="solaris" osversion="2.6">
+    <address>10.0.0.101</address>
+    <address>10.0.1.101</address>
+  </server>
+  <server name="gobi" osname="irix" osversion="6.5">
+    <address>10.0.0.102</address>
+  </server>
+  <server name="kalahari" osname="linux" osversion="2.0.34">
+    <address>10.0.0.103</address>
+    <address>10.0.1.103</address>
+  </server>
+</config>
diff --git a/test/files/empty.xml b/test/files/empty.xml
new file mode 100755
index 0000000..ce8cae9
--- /dev/null
+++ b/test/files/empty.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config/>
+
diff --git a/test/files/empty_and_text.xml b/test/files/empty_and_text.xml
new file mode 100755
index 0000000..e9bb1c3
--- /dev/null
+++ b/test/files/empty_and_text.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config>Hello</config>
+
diff --git a/test/files/empty_att.xml b/test/files/empty_att.xml
new file mode 100755
index 0000000..157a39a
--- /dev/null
+++ b/test/files/empty_att.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config att="Hello" />
+
diff --git a/test/files/empty_att_text.xml b/test/files/empty_att_text.xml
new file mode 100755
index 0000000..362e65e
--- /dev/null
+++ b/test/files/empty_att_text.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config att="Hello">Test</config>
+
diff --git a/test/files/invalid_config.xml b/test/files/invalid_config.xml
new file mode 100755
index 0000000..b59796a
--- /dev/null
+++ b/test/files/invalid_config.xml
@@ -0,0 +1,36 @@
+<!--
+-->
+
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config
+  <db>
+    <name>shop</name>
+    <user>maik</user>
+  </db>
+  <int-amount>42</int-amount>
+  <negative-int-amount>-42</negative-int-amount>
+  <float-amount>3.14</float-amount>
+  <negative-float-amount>-3.14</negative-float-amount>
+  <timer value='100' />
+  <environment-variable att='${PARAM2}'>This is ${PARAM_1} (${PARAM2}).</environment-variable>
+  <bools>
+    <no-1>
+      true
+    </no-1>
+    <no-2>false</no-2>
+    <no-3>1</no-3>
+    <no-4>0</no-4>
+    <no-5>yes</no-5>
+    <no-6>no</no-6>
+    <no-7>on</no-7>
+    <no-8>off</no-8>
+    <no-9>  TrUe </no-9>
+    <no-10>FaLsE  </no-10>
+    <no-11> yEs</no-11>
+    <no-12>  nO </no-12>
+    <no-13> oN   </no-13>
+    <no-14>  oFf  </no-14>
+  </bools>
+</config>
+
diff --git a/test/files/keyattr.xml b/test/files/keyattr.xml
new file mode 100755
index 0000000..129009a
--- /dev/null
+++ b/test/files/keyattr.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<opt>
+  <user login="grep" fullname="Gary R Epstein" />
+  <user login="stty" fullname="Simon T Tyson" />
+</opt>
+
diff --git a/test/files/opt.xml b/test/files/opt.xml
new file mode 100755
index 0000000..525ffef
--- /dev/null
+++ b/test/files/opt.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<opt><x>text1</x><y a="2">text2</y></opt>
+
diff --git a/test/files/original_pod.xml b/test/files/original_pod.xml
new file mode 100755
index 0000000..65fc86b
--- /dev/null
+++ b/test/files/original_pod.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+
+<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug">
+  <server name="sahara" osname="solaris" osversion="2.6">
+    <address>10.0.0.101</address>
+    <address>10.0.1.101</address>
+  </server>
+  <server name="gobi" osname="irix" osversion="6.5">
+    <address>10.0.0.102</address>
+  </server>
+  <server name="kalahari" osname="linux" osversion="2.0.34">
+    <address>10.0.0.103</address>
+    <address>10.0.1.103</address>
+  </server>
+</config>
diff --git a/test/files/response_checker.xml b/test/files/response_checker.xml
new file mode 100755
index 0000000..df22131
--- /dev/null
+++ b/test/files/response_checker.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<!--
+  Konfigurationsdatei f�r den ResponseChecker.
+-->
+<config>
+  <mailbox path='d:/usr/maik/project/valentins/response_checker_1.0.0/test/data' />
+
+  <response-types>
+    <response-type name='UnknownReason'    code='0' />
+    <response-type name='UnknownRecipient' code='1' />
+    <response-type name='AutoResponse'     code='2' />
+    <response-type name='QuotaExceeded'    code='3' />
+    <response-type name='SyntaxError'      code='4' />
+    <response-type name='UnknownDomain'    code='5' />
+    <response-type name='MailboxSuspended' code='6' />
+    <response-type name='VirusAlert'       code='7' />
+  </response-types>
+  
+  <response-patterns>
+    <patterns type='QuotaExceeded'>
+      <pattern>Benutzerquote wurde �berschritten</pattern>
+      <pattern>(user is )?over quota</pattern>
+      <pattern>Maildirectory voll</pattern>
+      <pattern>(quota|mailbox has) exceeded</pattern>
+      <pattern>allowed quota</pattern>
+      <pattern>mailbox (full|voll|exceeds)</pattern>
+      <pattern>(account|mailbox) is full</pattern>
+    </patterns>
+    <patterns type='AutoResponse'>
+      <pattern>Auto((-?reply)|-Submitted| Response|responder)</pattern>
+      <pattern>Abwesenheitsnotiz</pattern>
+      <pattern>automated respo</pattern>
+      <pattern>automatische</pattern>
+    </patterns>
+    <patterns type='UnknownRecipient'>
+      <pattern>benutzer unbekannt</pattern>
+      <pattern>no such mailbox</pattern>
+      <pattern>unbekannte E-Mail-Adresse</pattern>
+      <pattern>Unbekannter Empf�nger</pattern>
+      <pattern>User is (not known|unknown)</pattern>
+      <pattern>No such user</pattern>
+      <pattern>name is not recognized</pattern>
+      <pattern>unknown user</pattern>
+      <pattern>user unknown</pattern>
+      <pattern>user_unknown</pattern>
+      <pattern>invalid recipient</pattern>
+      <pattern>no mailbox</pattern>
+      <pattern>Recipient not allowed</pattern>
+      <pattern>not allowed to receive mail</pattern>
+    </patterns>
+    <patterns type='SyntaxError'>
+      <pattern>malformed address</pattern>
+    </patterns>
+    <patterns type='UnknownDomain'>
+      <pattern>host not found</pattern>
+      <pattern>bad destination</pattern>
+      <pattern>unknown subdomain</pattern>
+    </patterns>
+    <patterns type='MailboxSuspended'>
+      <pattern>mailbox has been suspended</pattern>
+      <pattern>mail-address is no longer valid</pattern>
+    </patterns>
+    <patterns type='VirusAlert'>
+      <pattern>Virus</pattern>
+    </patterns>
+    <patterns type='UnknownReason'>
+      <pattern>not listed in</pattern>
+      <pattern>did not reach the following</pattern>
+      <pattern>cannot be delivered</pattern>
+      <pattern>Nachricht nicht empfangen|zugestellt</pattern>
+      <pattern>konnte nicht ausgeliefert werden</pattern>
+      <pattern>message? could not be delivered</pattern>
+      <pattern>nger fehlgeschlagen</pattern>
+      <pattern>cannot find the path specified</pattern>
+      <pattern>Error During Delivery</pattern>
+      <pattern>failure notice</pattern>
+      <pattern>Undeliverable mail</pattern>
+      <pattern>undeliverable</pattern>
+      <pattern>Unzustellbar</pattern>
+      <pattern>Mailzustellung fehlgeschlagen</pattern>
+      <pattern>Undelivered Mail</pattern>
+      <pattern>Delivery failure</pattern>
+      <pattern>permanent fatal errors</pattern>
+      <pattern>returning message to sender</pattern>
+      <pattern>mailbox unavailable</pattern>
+      <pattern>recipients failed</pattern>
+      <pattern>does not exist</pattern>
+      <pattern>Warning: message</pattern>
+      <pattern>\berror</pattern>
+    </patterns>
+  </response-patterns>
+
+  <db>
+    <name>DBI:Mysql:shop</name>
+    <user></user>
+    <pwd></pwd>
+  </db>
+
+  <log4r_config>
+    <outputter type="StderrOutputter" name="console" level="DEBUG"/>
+
+    <outputter type="FileOutputter" name="logfile" level="DEBUG">
+      <filename>d:/usr/maik/project/valentins/response_checker_1.0.0/logs/response_checker.log</filename>
+      <!-- <trunc>false</trunc> -->
+      <formatter type="PatternFormatter" pattern="%d [%l] %m" />
+    </outputter>
+
+    <logger name="ResponseChecker"    level="DEBUG" outputters="logfile"/>
+    <logger name="ResponseClassifier" level="DEBUG" outputters="logfile"/>
+  </log4r_config> 
+</config>
+
diff --git a/test/files/srt.xml b/test/files/srt.xml
new file mode 100755
index 0000000..32e2b53
--- /dev/null
+++ b/test/files/srt.xml
@@ -0,0 +1,72 @@
+<?xml version='1.0' standalone='yes'?>
+
+<!--
+
+   This is an example of what a simple config file used by the System Release
+   Tool (SRT) might look like.  The file itself doesn't do anything other
+   than serve as a moderately complex test case for t/1_XMLin.t.
+
+   If you would like to find out more about the SRT, email the author at:
+
+     grantm@cpan.org
+
+-->
+   
+<opt>
+  <global tempdir="C:/Temp"
+	  httpproxy="http://10.1.1.5:8080/"
+	  proxyuser="foo"
+	  proxypswd="bar" >
+
+    <exclude>/_vt</exclude>
+    <exclude>/save\b</exclude>
+    <exclude>\.bak$</exclude>
+    <exclude>\.\$\$\$$</exclude>
+
+  </global>
+
+  <pubpath name="test1" title="web_source -&gt; web_target1">
+    <source label="web_source"
+            root="C:/webshare/web_source" />
+    <target label="web_target1"
+            root="C:/webshare/web_target1"
+            temp="C:/webshare/web_target1/temp" />
+
+    <dir>wwwroot</dir>
+
+    <package name="images" dir="wwwroot/images" />
+
+  </pubpath>
+
+  <pubpath name="test2" title="web_source -&gt; web_target1 &amp; web_target2">
+    <source label="web_source"
+            root="C:/webshare/web_source" />
+    <target label="web_target1"
+            root="C:/webshare/web_target1"
+            temp="C:/webshare/web_target1/temp" />
+    <target label="web_target2"
+            root="C:/webshare/web_target2"
+            temp="C:/webshare/web_target2/temp" />
+
+    <dir>wwwroot</dir>
+
+    <package name="images" dir="wwwroot/images" />
+    <package name="templates" dir="wwwroot/templates" />
+    <package name="bios" dir="wwwroot/staff/bios" />
+
+  </pubpath>
+
+  <pubpath name="test3" title="web_source -&gt; web_target1 via HTTP">
+    <source label="web_source"
+            root="C:/webshare/web_source" />
+    <target label="web_target1"
+            root="http://127.0.0.1/cgi-bin/srt_slave.plx"
+            noproxy="1" />
+
+    <dir>wwwroot</dir>
+
+    <addexclude>\.pdf$</addexclude>
+
+  </pubpath>
+
+</opt>
diff --git a/test/files/subdir/test2.xml b/test/files/subdir/test2.xml
new file mode 100755
index 0000000..0ead172
--- /dev/null
+++ b/test/files/subdir/test2.xml
@@ -0,0 +1 @@
+<opt location="files/subdir/test2.xml" />
diff --git a/test/files/symbol.xml b/test/files/symbol.xml
new file mode 100755
index 0000000..943daac
--- /dev/null
+++ b/test/files/symbol.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<atts>
+  <x>Hello</x>
+  <y>World</y>
+  <z>
+    <inner>Inner</inner>
+  </z>
+</atts>
+
diff --git a/test/files/tc_all.xml b/test/files/tc_all.xml
new file mode 100755
index 0000000..e9bb1c3
--- /dev/null
+++ b/test/files/tc_all.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config>Hello</config>
+
diff --git a/test/files/tc_file_in.xml b/test/files/tc_file_in.xml
new file mode 100755
index 0000000..e9bb1c3
--- /dev/null
+++ b/test/files/tc_file_in.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<config>Hello</config>
+
diff --git a/test/files/test1.xml b/test/files/test1.xml
new file mode 100755
index 0000000..25167b7
--- /dev/null
+++ b/test/files/test1.xml
@@ -0,0 +1 @@
+<opt location="files/test1.xml" />
diff --git a/test/files/to_hash.xml b/test/files/to_hash.xml
new file mode 100755
index 0000000..2f44411
--- /dev/null
+++ b/test/files/to_hash.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<a>
+  <b>
+    <c>Eins</c>
+    <c>Eins</c>
+    <c>Zwei</c>
+  </b>
+  <b>
+    <c>Drei</c>
+    <c>Zwei</c>
+    <c>
+      <d>yo</d>
+    </c>
+  </b>
+  <xyz>Hallo</xyz>
+  <abc>
+    <z>ZZZ</z>
+    <z/>
+    <z> </z>
+  </abc>
+  <att test='42' />
+  <att2 test='4711'>CONTENT</att2>
+  <element att="1">one</element>
+  <element att="2">two</element>
+  <element att="3">three</element>
+</a>
+
diff --git a/test/tc_all.xml b/test/tc_all.xml
new file mode 100755
index 0000000..016d52f
--- /dev/null
+++ b/test/tc_all.xml
@@ -0,0 +1 @@
+<opt location="tc_perl_in.xml" />
diff --git a/test/tc_attr_prefix.rb b/test/tc_attr_prefix.rb
new file mode 100755
index 0000000..404a611
--- /dev/null
+++ b/test/tc_attr_prefix.rb
@@ -0,0 +1,88 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+class TC_AttrPrefix < Test::Unit::TestCase # :nodoc:
+  def test_attr_prefix_option
+    xml_str = <<-XML_STR
+    <Customer id="12253">
+      <first_name>Joe</first_name>
+      <last_name>Joe</last_name>
+      <Address type="home"> 
+        <line1>211 Over There</line1>
+        <city>Jacksonville</city>
+        <state>FL</state>
+        <zip_code>11234</zip_code>
+      </Address>
+      <Address type="postal"> 
+        <line1>3535 Head Office</line1>
+        <city>Jacksonville</city>
+        <state>FL</state>
+        <zip_code>11234</zip_code>
+      </Address>
+    </Customer>
+    XML_STR
+
+    c = XmlSimple.xml_in xml_str, { 'ForceArray' => false, 'AttrPrefix' => true }
+
+    assert_equal(
+    {
+      "@id"=>"12253",
+      "first_name"=>"Joe",
+      "Address"=>
+      [
+        {
+          "city"=>"Jacksonville",
+          "line1"=>"211 Over There",
+          "zip_code"=>"11234",
+          "@type"=>"home",
+          "state"=>"FL"
+        },
+        {
+          "city"=>"Jacksonville",
+          "line1"=>"3535 Head Office",
+          "zip_code"=>"11234",
+          "@type"=>"postal",
+          "state"=>"FL"
+        }
+      ],
+      "last_name"=>"Joe"
+    },
+    c)
+
+    expected = REXML::Document.new <<-OUT
+    <opt id="12253">
+      <first_name>Joe</first_name>
+      <last_name>Joe</last_name>
+      <Address type="home">
+      <line1>211 Over There</line1>
+        <city>Jacksonville</city>
+        <state>FL</state>
+        <zip_code>11234</zip_code>
+      </Address>
+      <Address type="postal">
+      <line1>3535 Head Office</line1>
+        <city>Jacksonville</city>
+        <state>FL</state>
+        <zip_code>11234</zip_code>
+      </Address>
+    </opt>
+    OUT
+    e_root = expected.root
+    o_root = expected.root
+    assert_equal(e_root.elements.size, o_root.elements.size)
+    assert_equal(e_root.name, o_root.name)
+    assert_equal(e_root.attributes, o_root.attributes)
+    assert_equal(e_root.elements['/opt/first_name'].texts, o_root.elements['/opt/first_name'].texts)
+    assert_equal(e_root.elements['/opt/last_name'].texts, o_root.elements['/opt/last_name'].texts)
+    %w(home postal).each do |addr_type|
+      e_address = e_root.elements["/opt/Address[@type='#{addr_type}']"]
+      o_address = o_root.elements["/opt/Address[@type='#{addr_type}']"]
+      %w(line1 city state zip_code).each do |element|
+        assert_equal(e_address.elements[element].text, o_address.elements[element].text)
+      end
+    end
+  end
+end
+
diff --git a/test/tc_curtis.rb b/test/tc_curtis.rb
new file mode 100755
index 0000000..43c6dcf
--- /dev/null
+++ b/test/tc_curtis.rb
@@ -0,0 +1,59 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+# This test class is named after Curtis Schofield, who
+# reported the bug whose absence is tested by this class :-)
+class TC_Curtis < Test::Unit::TestCase # :nodoc:
+  def setup
+    @test_file = File.join(File.dirname(__FILE__), 'files', 'curtis.xml')
+  end
+  
+  def test_empty_attributes
+    expected = {
+      "logdir" => "/var/log/foo/",
+      "server" => [
+        {
+          "name" => "sahara",
+          "osversion" => "2.6",
+          "osname" => "solaris",
+          "address" => [ "10.0.0.101", "10.0.1.101" ]
+        },
+        {
+          "name" => "gobi",
+          "osversion" => "6.5",
+          "osname" => "irix",
+        },
+        {
+          "name" => "kalahari",
+          "osversion" => "2.0.34",
+          "osname" => "linux",
+          "address" => [ "10.0.0.103", "10.0.1.103" ]
+        }
+      ],
+      "debugfile" => "/tmp/foo.debug"
+    }
+    xml = XmlSimple.xml_in(@test_file, { 'NormalizeSpace' => 2 })
+    assert_equal(expected, xml)
+    xml = XmlSimple.xml_in(@test_file, { 'SuppressEmpty' => true })
+    assert_equal(expected, xml)
+  end
+
+  def test_with_noattr
+    expected = {
+      "server" => [
+        {
+          "address" => [ "10.0.0.101", "10.0.1.101" ]
+        },
+        {
+          "address" => [ "10.0.0.103", "10.0.1.103" ]
+        }
+      ],
+    }
+    xml = XmlSimple.xml_in(@test_file, { 'NoAttr' => true, 'SuppressEmpty' => true })
+    assert_equal(expected, xml)
+  end
+end
+
+# vim:sw=2
diff --git a/test/tc_file_in.rb b/test/tc_file_in.rb
new file mode 100755
index 0000000..f88d437
--- /dev/null
+++ b/test/tc_file_in.rb
@@ -0,0 +1,423 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+class TC_File_In < Test::Unit::TestCase # :nodoc:
+  def test_original
+    original_pod = File.join(File.dirname(__FILE__), 'files', 'original_pod.xml')
+    config = XmlSimple.new
+    expected = {
+      'logdir'        => '/var/log/foo/',
+      'debugfile'     => '/tmp/foo.debug',
+
+      'server'        => {
+        'sahara'        => {
+          'osversion'     => '2.6',
+          'osname'        => 'solaris',
+          'address'       => [ '10.0.0.101', '10.0.1.101' ]
+        },
+
+        'gobi'          => {
+          'osversion'     => '6.5',
+          'osname'        => 'irix',
+          'address'       => '10.0.0.102'
+        },
+
+        'kalahari'      => {
+          'osversion'     => '2.0.34',
+          'osname'        => 'linux',
+          'address'       => [ '10.0.0.103', '10.0.1.103' ]
+        }
+      }
+    }
+    assert_equal(expected, config.xml_in(original_pod, { 'force_array' => false, 'key_attr' => %w(name) }))
+
+    expected = {
+      'logdir'        => '/var/log/foo/',
+      'debugfile'     => '/tmp/foo.debug',
+
+      'server'        => {
+        'sahara'        => {
+          'osversion'     => '2.6',
+          'osname'        => 'solaris',
+          'address'       => [ '10.0.0.101', '10.0.1.101' ]
+        },
+
+        'gobi'          => {
+          'osversion'     => '6.5',
+          'osname'        => 'irix',
+          'address'       => [ '10.0.0.102' ]
+        },
+
+        'kalahari'      => {
+          'osversion'     => '2.0.34',
+          'osname'        => 'linux',
+          'address'       => [ '10.0.0.103', '10.0.1.103' ]
+        }
+      }
+    }
+    assert_equal(expected, config.xml_in(original_pod, { 'key_attr' => %w(name) }))
+    assert_equal(expected, config.xml_in(original_pod, { 'key_attr' => 'name' }))
+  end
+
+  def test_keep_root
+    test_file = File.join(File.dirname(__FILE__), 'files', 'to_hash.xml')
+    config = XmlSimple.new
+    expected = {
+      'abc' => [
+        {
+          'z' => ['ZZZ', {}, {}]
+        }
+      ],
+      'b'   => [
+        {
+          'c' => ['Eins', 'Eins', 'Zwei']
+        },
+        {
+          'c' => [
+            'Drei',
+            'Zwei',
+            { 'd' => [ 'yo' ] }
+          ]
+        }
+      ],
+      'xyz'  => [ 'Hallo' ],
+      'att'  => [ { 'test' => '42' } ],
+      'att2' => [ { 'test' => '4711', 'content' => 'CONTENT' } ],
+      'element' => [
+        {
+          'att'     => '1',
+          'content' => 'one'
+        },
+        {
+          'att'     => '2',
+          'content' => 'two'
+        },
+        {
+          'att'     => '3',
+          'content' => 'three'
+        },
+      ],
+    }
+    assert_equal(expected, config.xml_in(test_file))
+
+    config = XmlSimple.new
+    expected = {
+      'a' => [
+        {
+          'att' => [
+            {
+              'test' => '42'
+            }
+          ],
+          'abc' => [
+            {
+              'z' => [
+                'ZZZ',
+                {},
+                {}
+              ]
+            }
+          ],
+          'att2' => [
+            {
+              'content' => 'CONTENT',
+              'test' => '4711'
+            }
+          ],
+          'b' => [
+            {
+              'c' => [
+                'Eins',
+                'Eins',
+                'Zwei'
+              ]
+            },
+            {
+              'c' => [
+                'Drei',
+                'Zwei',
+                {
+                  'd' => [
+                    'yo'
+                  ]
+                }
+              ]
+            }
+          ],
+          'element' => [
+            {
+              'att' => '1',
+              'content' => 'one'
+            },
+            {
+              'att' => '2',
+              'content' => 'two'
+            },
+            {
+              'att' => '3',
+              'content' => 'three'
+            }
+          ],
+          'xyz' => [
+            'Hallo'
+          ]
+        }
+      ]
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'keep_root' => true }))
+
+    config = XmlSimple.new({ 'keep_root' => true })
+    assert_equal(expected, config.xml_in(test_file))
+
+    expected = {
+      'abc' => [
+        {
+          'z' => [ 'ZZZ' ]
+        }
+      ],
+      'b'   => [
+        {
+          'c' => ['Eins', 'Eins', 'Zwei']
+        },
+        {
+          'c' => [
+            'Drei',
+            'Zwei',
+            { 'd' => [ 'yo' ] }
+          ]
+        }
+      ],
+      'xyz'  => [ 'Hallo' ],
+      'att'  => [ { 'test' => '42' } ],
+      'att2' => [ { 'test' => '4711', 'content' => 'CONTENT' } ],
+      'element' => [
+        {
+          'att'     => '1',
+          'content' => 'one'
+        },
+        {
+          'att'     => '2',
+          'content' => 'two'
+        },
+        {
+          'att'     => '3',
+          'content' => 'three'
+        },
+      ],
+    }
+    assert_equal(expected, XmlSimple.xml_in(test_file, { 'suppress_empty' => true }))
+
+    config = XmlSimple.new({ 'suppress_empty' => true })
+    assert_equal(expected, config.xml_in(test_file))
+  end
+
+  def test_force_content
+    test_file = File.join(File.dirname(__FILE__), 'files', 'opt.xml')
+    config = XmlSimple.new
+    expected = {
+      'x' => [ 'text1' ],
+      'y' => [ { 'a' => '2', 'content' => 'text2' } ]
+    }
+    assert_equal(expected, config.xml_in(test_file))
+
+    expected = {
+      'x' => 'text1',
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => false }))
+
+    expected = {
+      'x' => [ {             'content' => 'text1' } ],
+      'y' => [ { 'a' => '2', 'content' => 'text2' } ]
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_content' => true }))
+
+    expected = {
+      'x' => {             'content' => 'text1' },
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => false, 'force_content' => true }))
+
+    expected = {
+      'x' => [ {             'text' => 'text1' } ],
+      'y' => [ { 'a' => '2', 'text' => 'text2' } ]
+    }
+    assert_equal(expected, config.xml_in(test_file, {'content_key' => 'text', 'force_content' => true}))
+
+    expected = {
+      'x' => [ 'text1' ],
+      'y' => [ { 'a' => '2', 'text' => 'text2' } ]
+    }
+    assert_equal(expected, config.xml_in(test_file, {'content_key' => 'text', 'force_content' => false}))
+
+    expected = {
+      'x' => 'text1',
+      'y' => { 'a' => '2', 'text' => 'text2' }
+    }
+    assert_equal(expected, config.xml_in(test_file, {
+      'force_array'   => false,
+      'content_key'   => 'text',
+      'force_content' => false
+    }))
+  end
+
+  def test_force_array
+    test_file = File.join(File.dirname(__FILE__), 'files', 'opt.xml')
+    config = XmlSimple.new
+    expected = {
+      'x' => ['text1'],
+      'y' => [{ 'a' => '2', 'content' => 'text2' }]
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => true }))
+
+    expected = {
+      'x' => ['text1'],
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => ['x']}))
+
+    expected = {
+      'x' => 'text1',
+      'y' => [{ 'a' => '2', 'content' => 'text2' }]
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => ['y']}))
+
+    expected = {
+      'x' => ['text1'],
+      'y' => [{ 'a' => '2', 'content' => 'text2' }]
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => ['x', 'y']}))
+
+    expected = {
+      'x' => 'text1',
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => []}))
+
+    expected = {
+      'x' => 'text1',
+      'y' => { 'a' => '2', 'content' => 'text2' }
+    }
+    assert_equal(expected, config.xml_in(test_file, { 'force_array' => false }))
+  end
+
+  def test_no_attr
+    opt_file = File.join(File.dirname(__FILE__), 'files', 'opt.xml')
+    att_file = File.join(File.dirname(__FILE__), 'files', 'att.xml')
+    config = XmlSimple.new
+    expected = {
+      'x' => [ { 'a' => '1', 'b' => '2', 'content' => 'Hello' } ],
+      'y' => [ { 'c' => '5',             'content' => 'World' } ],
+      'z' => [ { 'inner' => [ 'Inner' ] } ],
+    }
+    assert_equal(expected, config.xml_in(att_file))
+
+    expected = {
+      'x' => [ 'Hello' ],
+      'y' => [ 'World' ],
+      'z' => [ { 'inner' => [ 'Inner' ] } ],
+    }
+    assert_equal(expected, config.xml_in(att_file, { 'no_attr' => true}))
+
+    config = XmlSimple.new
+    expected = {
+      'x' => [ 'text1' ],
+      'y' => [ 'text2' ]
+    }
+    assert_equal(expected, config.xml_in(opt_file, { 'no_attr' => true}))
+
+    expected = {
+      'x' => [ { 'content'=> 'text1'} ],
+      'y' => [ { 'content'=> 'text2'} ]
+    }
+    assert_equal(expected, config.xml_in(opt_file, { 'force_content' => true, 'no_attr' => true}))
+
+    config = XmlSimple.new
+    expected = {
+      'opt' => [
+        {
+          'x' => [ { 'content'=> 'text1'} ],
+          'y' => [ { 'content'=> 'text2'} ]
+        }
+      ]
+    }
+    assert_equal(expected, config.xml_in(opt_file, { 'keep_root' => true, 'force_content' => true, 'no_attr' => true}))
+  end
+
+  def test_minimum
+    config = XmlSimple.new
+    assert_equal({}, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty.xml')))
+    assert_equal({'config' => [{}]}, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty.xml'), { 'keep_root' => true }))
+
+    config = XmlSimple.new
+    assert_equal('Hello', config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty_and_text.xml')))
+    assert_equal({'config' => ['Hello']}, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty_and_text.xml'), { 'keep_root' => true}))
+
+    config = XmlSimple.new
+    assert_equal({ 'att' => 'Hello'}, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty_att.xml')))
+    assert_equal({'config' => [ {'att' => 'Hello'} ]}, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty_att.xml'), { 'keep_root' => true }))
+
+    config = XmlSimple.new
+    assert_equal({ 'att' => 'Hello', 'content' => 'Test'}, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty_att_text.xml')))
+    assert_equal({
+      'config' => [
+        {
+          'att'     => 'Hello',
+          'content' => 'Test'
+        }
+      ]
+    }, config.xml_in(File.join(File.dirname(__FILE__), 'files', 'empty_att_text.xml'), { 'keep_root' => true }))
+  end
+
+  def test_key_attr
+    keyattr_file = File.join(File.dirname(__FILE__), 'files', 'keyattr.xml')
+    config = XmlSimple.new
+    expected = {
+      'user' => {
+        'stty' => {
+          'fullname' => 'Simon T Tyson',
+          'login'    => 'stty'
+        },
+        'grep' => {
+          'fullname' => 'Gary R Epstein',
+          'login'    => 'grep'
+        }
+      }
+    }
+    assert_equal(expected, config.xml_in(keyattr_file, { 'key_attr' => { 'user' => '+login' } }))
+
+    expected = {
+      'user' => {
+        'stty' => {
+          'fullname' => 'Simon T Tyson',
+          '-login'   => 'stty'
+        },
+        'grep' => {
+          'fullname' => 'Gary R Epstein',
+          '-login'   => 'grep'
+        }
+      }
+    }
+    assert_equal(expected, config.xml_in(keyattr_file, { 'key_attr' => { 'user' => '-login' } }))
+  end
+
+  def test_conversions
+    conv_file = File.join(File.dirname(__FILE__), 'files', 'conversions.xml')
+    conversions = {
+      /^total|failed$/ => lambda{|v| v.to_i},
+      /^status$/ => lambda {|v| v.downcase}
+    }
+
+    expected = {
+      'status' => 'ok',
+      'total' => 10,
+      'failed' => 2
+    }
+
+    result = XmlSimple.xml_in(conv_file, :conversions => conversions, :forcearray => false)
+    assert_equal(expected, result)
+  end
+end
+
diff --git a/test/tc_markup.rb b/test/tc_markup.rb
new file mode 100755
index 0000000..91c54b8
--- /dev/null
+++ b/test/tc_markup.rb
@@ -0,0 +1,21 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+# This test case checks if a bug regarding markup encoding
+# reported by Yan Zhang (Yan.Zhang (at) fedexkinkos.com)
+# has been fixed.
+class TC_Markup < Test::Unit::TestCase # :nodoc:
+  def test_markup
+    doc = <<-DOC
+    <businessCustNames>
+      <businessCustName>The&#39;s Heating &amp; Air</businessCustName>
+    </businessCustNames>
+    DOC
+    expected = { 'businessCustName' => ["The's Heating & Air"] }
+    xml = XmlSimple.xml_in(doc)
+    assert_equal(expected, xml)
+  end
+end
+
diff --git a/test/tc_nick.rb b/test/tc_nick.rb
new file mode 100755
index 0000000..ae5aeeb
--- /dev/null
+++ b/test/tc_nick.rb
@@ -0,0 +1,36 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+class NodeToTextTests < Test::Unit::TestCase
+  def setup
+    @xmlin = XmlSimple.new
+    @element = REXML::Element.new("abc")
+    @text = REXML::Text.new("<abc/>")
+    @attribute = REXML::Attribute.new("name", "&lt;abc/&gt;")
+    @element.add_attribute(@attribute)
+    @element.add_text(@text)
+  end
+
+  def test_node_to_text_on_element
+    assert_equal "<abc/>", @xmlin.send(:node_to_text, @element)
+  end
+  
+  def test_node_to_text_on_text
+    assert_equal "<abc/>", @xmlin.send(:node_to_text, @text)
+  end
+  
+  def test_node_to_text_on_attribute
+    assert_equal "<abc/>", @xmlin.send(:node_to_text, @attribute)
+  end
+  
+  def test_node_to_text_on_doubly_normalized_attribute
+    @attribute = REXML::Attribute.new("name", "&amp;lt;abc/&amp;gt;")
+    assert_equal "&lt;abc/&gt;", @xmlin.send(:node_to_text, @attribute)
+  end
+  
+  def test_node_to_text_on_nil
+    assert_nil @xmlin.send(:node_to_text, nil)
+  end
+end
diff --git a/test/tc_out.rb b/test/tc_out.rb
new file mode 100755
index 0000000..c641e73
--- /dev/null
+++ b/test/tc_out.rb
@@ -0,0 +1,186 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+class TC_Out < Test::Unit::TestCase # :nodoc:
+  def test_simple_structure
+    hash = {
+      'opt' => [
+        {
+          'x' => [ { 'content'=> 'text1'} ],
+          'y' => [ { 'content'=> 'text2'} ]
+        }
+      ]
+    }
+    expected = <<"END_OF_XML"
+<opt>
+  <opt>
+    <x>text1</x>
+    <y>text2</y>
+  </opt>
+</opt>
+END_OF_XML
+
+    assert_equal(expected, XmlSimple.xml_out(hash))
+  end
+
+  def test_keep_root
+    hash = {
+      'opt' => [
+        {
+          'x' => [ { 'content'=> 'text1'} ],
+          'y' => [ { 'content'=> 'text2'} ]
+        }
+      ]
+    }
+    expected = <<"END_OF_XML"
+<opt>
+  <x>text1</x>
+  <y>text2</y>
+</opt>
+END_OF_XML
+
+    assert_equal(expected, XmlSimple.xml_out(hash, { 'keep_root' => true }))
+  end
+
+  def test_original
+    hash = {
+      'logdir'        => '/var/log/foo/',
+      'debugfile'     => '/tmp/foo.debug',
+
+      'server'        => {
+        'sahara'        => {
+          'osversion'     => '2.6',
+          'osname'        => 'solaris',
+          'address'       => [ '10.0.0.101', '10.0.1.101' ]
+        },
+
+        'gobi'          => {
+          'osversion'     => '6.5',
+          'osname'        => 'irix',
+          'address'       => '10.0.0.102'
+        },
+
+        'kalahari'      => {
+          'osversion'     => '2.0.34',
+          'osname'        => 'linux',
+          'address'       => [ '10.0.0.103', '10.0.1.103' ]
+        }
+      }
+    }
+
+    expected = <<"END_OF_XML"
+<opt logdir="/var/log/foo/" debugfile="/tmp/foo.debug">
+  <server>
+    <sahara osversion="2.6" osname="solaris">
+      <address>10.0.0.101</address>
+      <address>10.0.1.101</address>
+    </sahara>
+    <gobi osversion="6.5" osname="irix" address="10.0.0.102" />
+    <kalahari osversion="2.0.34" osname="linux">
+      <address>10.0.0.103</address>
+      <address>10.0.1.103</address>
+    </kalahari>
+  </server>
+</opt>
+END_OF_XML
+    assert_equal(expected, XmlSimple.xml_out(hash))
+  end
+
+  def test_xyz
+    hash = {
+      'abc' => [
+        {
+          'z' => ['ZZZ', {}, {}]
+        }
+      ],
+      'b'   => [
+        {
+          'c' => ['Eins', 'Eins', 'Zwei']
+        },
+        {
+          'c' => [
+            'Drei',
+            'Zwei',
+            { 'd' => [ 'yo' ] }
+          ]
+        }
+      ],
+      'xyz'  => [ 'Hallo' ],
+      'att'  => [ { 'test' => '42' } ],
+      'att2' => [ { 'test' => '4711', 'content' => 'CONTENT' } ],
+      'element' => [
+        {
+          'att'     => '1',
+          'content' => 'one'
+        },
+        {
+          'att'     => '2',
+          'content' => 'two'
+        },
+        {
+          'att'     => '3',
+          'content' => 'three'
+        },
+      ],
+    }
+    expected = <<"END_OF_XML"
+<opt>
+  <abc>
+    <z>ZZZ</z>
+    <z></z>
+    <z></z>
+  </abc>
+  <b>
+    <c>Eins</c>
+    <c>Eins</c>
+    <c>Zwei</c>
+  </b>
+  <b>
+    <c>Drei</c>
+    <c>Zwei</c>
+    <c>
+      <d>yo</d>
+    </c>
+  </b>
+  <xyz>Hallo</xyz>
+  <att test="42" />
+  <att2 test="4711">CONTENT</att2>
+  <element att="1">one</element>
+  <element att="2">two</element>
+  <element att="3">three</element>
+</opt>
+END_OF_XML
+
+    assert_equal(expected, XmlSimple.xml_out(hash))
+  end
+
+  def test_selfclose
+    hash = {
+      'root' => [
+        {
+          'empty' => ['text', {}, {}]
+        }
+      ]
+    }
+    expected = <<"END_OF_XML"
+<opt>
+  <root>
+    <empty>text</empty>
+    <empty />
+    <empty />
+  </root>
+</opt>
+END_OF_XML
+
+    assert_equal(expected, XmlSimple.xml_out(hash, 'selfclose' => true))
+  end
+
+  def test_output_with_symbols
+    test1 = { :foo => 'abc' }
+    expected = "<opt foo=\"abc\" />\n"
+    output = XmlSimple.xml_out(test1)
+    assert_equal(output, expected)
+  end
+end
diff --git a/test/tc_perl_in.rb b/test/tc_perl_in.rb
new file mode 100755
index 0000000..4cab2b1
--- /dev/null
+++ b/test/tc_perl_in.rb
@@ -0,0 +1,1242 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+# The test cases below are copied from the original Perl version,
+# because I wanted to behave the Ruby version exactly as the Perl
+# version. I left some comments, that maybe do not make a lot of
+# sense in the current Ruby version just to make it easier to find
+# changes between the current and future Perl versions of the
+# module.
+# Please note, that a major difference between the Perl and the Ruby
+# version is, that the defaults of the options 'force_array' and
+# 'key_attr' have changed.
+class TC_Perl_In < Test::Unit::TestCase # :nodoc:
+  def test_perl_test_cases
+    opt = XmlSimple.xml_in(%q(<opt name1="value1" name2="value2"></opt>), {
+      'force_array' => false,
+      'key_attr'    => %w(name, key, id)
+    })
+    expected = {
+      'name1' => 'value1',
+      'name2' => 'value2'
+    }
+    assert_equal(expected, opt)
+
+    # Now try a slightly more complex one that returns the same value
+    opt = XmlSimple.xml_in(%q(
+      <opt> 
+        <name1>value1</name1>
+        <name2>value2</name2>
+      </opt>
+    ), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(expected, opt)
+
+    # And something else that returns the same
+    opt = XmlSimple.xml_in(%q(<opt name1="value1"
+    name2="value2" />), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(expected, opt)
+
+    # Try something with two lists of nested values 
+    opt = XmlSimple.xml_in(%q(
+      <opt> 
+        <name1>value1.1</name1>
+        <name1>value1.2</name1>
+        <name1>value1.3</name1>
+        <name2>value2.1</name2>
+        <name2>value2.2</name2>
+        <name2>value2.3</name2>
+    </opt>), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({
+      'name1' => [ 'value1.1', 'value1.2', 'value1.3' ],
+      'name2' => [ 'value2.1', 'value2.2', 'value2.3' ]
+    }, opt)
+
+    # Now a simple nested hash
+    opt = XmlSimple.xml_in(%q(
+      <opt> 
+        <item name1="value1" name2="value2" />
+      </opt>), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({
+      'item' => {
+        'name1' => 'value1',
+        'name2' => 'value2'
+      }
+    }, opt)
+
+    # Now a list of nested hashes
+    opt = XmlSimple.xml_in(%q(
+      <opt> 
+        <item name1="value1" name2="value2" />
+        <item name1="value3" name2="value4" />
+      </opt>), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({
+      'item' => [
+        { 
+          'name1' => 'value1',
+          'name2' => 'value2'
+        },
+        {
+          'name1' => 'value3',
+          'name2' => 'value4'
+        }
+	  ]
+    }, opt)
+
+    # Now a list of nested hashes transformed into a hash using former
+    # default key names.
+    string = %q(
+      <opt> 
+        <item name="item1" attr1="value1" attr2="value2" />
+        <item name="item2" attr1="value3" attr2="value4" />
+      </opt>
+    )
+    target = {
+      'item' => {
+        'item1' => {
+          'attr1' => 'value1',
+          'attr2' => 'value2'
+        },
+        'item2' => {
+          'attr1' => 'value3',
+          'attr2' => 'value4'
+        }
+      }
+    }
+    opt = XmlSimple.xml_in(string, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(target, opt)
+
+    # Same thing left as an array by suppressing former default key names.
+    target = {
+      'item' => [
+        {
+          'name'  => 'item1',
+          'attr1' => 'value1',
+          'attr2' => 'value2'
+        },
+        {
+          'name'  => 'item2',
+          'attr1' => 'value3',
+          'attr2' => 'value4'
+        }
+      ]
+    }
+    opt = XmlSimple.xml_in(string, { 'force_array' => false })
+    assert_equal(target, opt)
+
+    # Same again with alternative key suppression
+    opt = XmlSimple.xml_in(string, { 'key_attr' => {} })
+    assert_equal(target, opt)
+
+    # Try the other two "default" key attribute names (they are no
+    # default values in the Ruby version.)
+    opt = XmlSimple.xml_in(%q(
+      <opt> 
+        <item key="item1" attr1="value1" attr2="value2" />
+        <item key="item2" attr1="value3" attr2="value4" />
+      </opt>
+    ), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({
+      'item' => {
+        'item1' => {
+          'attr1' => 'value1',
+          'attr2' => 'value2'
+        },
+        'item2' => {
+          'attr1' => 'value3',
+          'attr2' => 'value4'
+        }
+      }
+    }, opt)
+
+    opt = XmlSimple.xml_in(%q(
+      <opt> 
+        <item id="item1" attr1="value1" attr2="value2" />
+        <item id="item2" attr1="value3" attr2="value4" />
+      </opt>
+    ), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({
+      'item' => {
+        'item1' => {
+          'attr1' => 'value1',
+          'attr2' => 'value2'
+        },
+        'item2' => {
+          'attr1' => 'value3',
+          'attr2' => 'value4'
+        }
+      }
+    }, opt)
+
+    # Similar thing using non-standard key names
+    xml = %q(
+      <opt> 
+        <item xname="item1" attr1="value1" attr2="value2" />
+        <item xname="item2" attr1="value3" attr2="value4" />
+      </opt>)
+
+    target = {
+      'item' => {
+        'item1' => {
+          'attr1' => 'value1',
+          'attr2' => 'value2'
+        },
+        'item2' => {
+          'attr1' => 'value3',
+          'attr2' => 'value4'
+        }
+      }
+    }
+
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(xname) })
+    assert_equal(target, opt)
+
+    # And with precise element/key specification
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => { 'item' => 'xname' } })
+    assert_equal(target, opt)
+
+    # Same again but with key field further down the list
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(wibble xname) })
+    assert_equal(target, opt)
+
+    # Same again but with key field supplied as scalar
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'keyattr' => %w(xname) })
+    assert_equal(target, opt)
+
+    # Same again but with mixed-case option name
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'KeyAttr' => %w(xname) })
+    assert_equal(target, opt)
+
+    # Same again but with underscores in option name
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(xname) })
+    assert_equal(target, opt)
+
+    # Weird variation, not exactly what we wanted but it is what we expected 
+    # given the current implementation and we don't want to break it accidently
+    xml = %q(
+     <opt>
+       <item id="one" value="1" name="a" />
+       <item id="two" value="2" />
+       <item id="three" value="3" />
+     </opt>)
+
+    target = {
+      'item' => {
+        'three' => {
+          'value' => '3'
+        },
+        'a' => {
+          'value' => '1',
+          'id'    => 'one'
+        },
+        'two' => { 
+          'value' => '2'
+        }
+      }
+    }
+       
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(target, opt)
+
+    # Or somewhat more as one might expect
+    target = {
+      'item' => {
+        'one' => {
+          'value' => '1',
+          'name'  => 'a' 
+        },
+        'two' => {
+          'value' => '2'
+        },
+        'three' => {
+          'value' => '3'
+        }
+      }
+    }
+       
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => { 'item' => 'id' } })
+    assert_equal(target, opt)
+
+    # Now a somewhat more complex test of targetting folding
+    xml = %q(
+      <opt>
+        <car license="SH6673" make="Ford" id="1">
+          <option key="1" pn="6389733317-12" desc="Electric Windows"/>
+          <option key="2" pn="3735498158-01" desc="Leather Seats"/>
+          <option key="3" pn="5776155953-25" desc="Sun Roof"/>
+        </car>
+        <car license="LW1804" make="GM"   id="2">
+          <option key="1" pn="9926543-1167" desc="Steering Wheel"/>
+        </car>
+      </opt>)
+
+    target = {
+      'car' => {
+        'LW1804' => {
+          'id'     => '2',
+          'make'   => 'GM',
+          'option' => {
+            '9926543-1167' => {
+              'key'  => '1',
+              'desc' => 'Steering Wheel'
+            }
+          }
+        },
+        'SH6673' => {
+          'id'     => '1',
+          'make'   => 'Ford',
+          'option' => {
+            '6389733317-12' => {
+              'key'  => '1', 
+              'desc' => 'Electric Windows'
+            },
+            '3735498158-01' => {
+              'key'  => '2',
+              'desc' => 'Leather Seats'
+            },
+            '5776155953-25' => {
+              'key'  => '3',
+              'desc' => 'Sun Roof'
+            }
+          }
+        }
+      }
+    }
+    
+    opt = XmlSimple.xml_in(xml, { 'key_attr' => { 'car' => 'license', 'option' => 'pn' }});
+    assert_equal(target, opt)
+
+    # Now try leaving the keys in place
+    target = {
+      'car' => {
+        'LW1804' => {
+          'id'     => '2',
+          'make'   => 'GM',
+          'option' => {
+            '9926543-1167' => {
+              'key'  => '1',
+              'desc' => 'Steering Wheel',
+              '-pn'  => '9926543-1167'
+            }
+          },
+          'license' => 'LW1804'
+        },
+        'SH6673' => {
+          'id'     => '1',
+          'make'   => 'Ford',
+          'option' => {
+            '6389733317-12' => {
+              'key'  => '1',
+              'desc' => 'Electric Windows',
+              '-pn'  => '6389733317-12'
+            },
+            '3735498158-01' => {
+              'key'  => '2',
+              'desc' => 'Leather Seats',
+              '-pn'  => '3735498158-01'
+            },
+            '5776155953-25' => {
+              'key'  => '3',
+              'desc' => 'Sun Roof',
+              '-pn'  => '5776155953-25'
+            }
+          },
+          'license' => 'SH6673'
+        }
+      }
+    }
+    
+    opt = XmlSimple.xml_in(xml, { 'key_attr' => { 'car' => '+license', 'option' => '-pn' }})
+    assert_equal(target, opt)
+
+    # Confirm the stringifying references bug is fixed
+    xml = %q(
+      <opt>
+        <item>
+          <name><firstname>Bob</firstname></name>
+          <age>21</age>
+        </item>
+        <item>
+          <name><firstname>Kate</firstname></name>
+          <age>22</age>
+        </item>
+      </opt>)
+      
+    target = {
+      'item' => [
+        {
+          'age'  => '21',
+          'name' => {
+            'firstname' => 'Bob'
+          }
+        },
+        {
+          'age'  => '22',
+          'name' => {
+            'firstname' => 'Kate'
+          }
+        },
+      ]
+    }
+      
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(target, opt)
+
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => { 'item' => 'name' }})
+    assert_equal(target, opt)
+
+    # Make sure that the root element name is preserved if we ask for it
+    target = XmlSimple.xml_in("<opt>#{xml}</opt>", {
+      'key_attr' => { 'car' => '+license', 'option' => '-pn' }
+    })
+    opt = XmlSimple.xml_in(xml, {
+      'keep_root' => true,
+      'key_attr'  => { 'car' => '+license', 'option' => '-pn' }
+    })
+    assert_equal(target, opt)
+
+    # confirm that CDATA sections parse correctly
+    xml = %q{<opt><cdata><![CDATA[<greeting>Hello, world!</greeting>]]></cdata></opt>};
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) });
+    assert_equal({ 'cdata' => '<greeting>Hello, world!</greeting>' }, opt)
+
+    xml = %q{<opt><x><![CDATA[<y>one</y>]]><![CDATA[<y>two</y>]]></x></opt>};
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) });
+    assert_equal({ 'x' => '<y>one</y><y>two</y>' }, opt)
+
+    # Try parsing a named external file
+    opt = XmlSimple.xml_in(File.join(File.dirname(__FILE__), 'files', 'test1.xml'), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({ 'location' => 'files/test1.xml' }, opt)
+
+    # Try parsing default external file (scriptname.xml in script directory)
+    # I have disabled this test for now, because I did not have time to make
+    # it work. The problem is that the environment of the test runner is
+    # completely different from the environment of the actual test case.
+    # opt = XmlSimple.xml_in(nil, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    # assert_equal({ 'location' => 'tc_perl_in.xml' }, opt)
+
+    # Try parsing named file in a directory in the searchpath
+    opt = XmlSimple.xml_in('test2.xml', {
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'search_path' => ['dir1', 'dir2', File.join(File.dirname(__FILE__), 'files', 'subdir')]
+    })
+    assert_equal({ 'location' => 'files/subdir/test2.xml' }, opt)
+
+    # Ensure we get expected result if file does not exist
+    assert_raises(ArgumentError) {
+      XmlSimple.xml_in('bogusfile.xml', { 'searchpath' => %w(. ./files) } )
+    }
+
+    # Try parsing from an IO::Handle 
+    fh = File.new(File.join(File.dirname(__FILE__), 'files', '1_xml_in.xml'))
+    opt = XmlSimple.xml_in(fh, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal('files/1_xml_in.xml', opt['location'])
+
+    # Try parsing from STDIN
+    $stdin.reopen(File.new(File.join(File.dirname(__FILE__), 'files', '1_xml_in.xml')))
+    opt = XmlSimple.xml_in('-', { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal('files/1_xml_in.xml', opt['location'])
+
+    # Confirm anonymous array handling works in general
+    opt = XmlSimple.xml_in(%q(
+      <opt>
+        <row>
+          <anon>0.0</anon><anon>0.1</anon><anon>0.2</anon>
+        </row>
+        <row>
+          <anon>1.0</anon><anon>1.1</anon><anon>1.2</anon>
+        </row>
+        <row>
+          <anon>2.0</anon><anon>2.1</anon><anon>2.2</anon>
+        </row>
+      </opt>), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({
+      'row' => [
+	     [ '0.0', '0.1', '0.2' ],
+	     [ '1.0', '1.1', '1.2' ],
+	     [ '2.0', '2.1', '2.2' ]
+      ]
+    }, opt)
+
+    # Confirm anonymous array handling works in special top level case
+    opt = XmlSimple.xml_in(%q(
+      <opt>
+        <anon>one</anon>
+        <anon>two</anon>
+        <anon>three</anon>
+      </opt>), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(%w(one two three), opt)
+
+    opt = XmlSimple.xml_in(%q(
+      <opt>
+        <anon>1</anon>
+        <anon>
+          <anon>2.1</anon>
+          <anon>
+	        <anon>2.2.1</anon>
+	        <anon>2.2.2</anon>
+          </anon>
+        </anon>
+      </opt>), { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal([
+      '1',
+      [
+        '2.1', [
+          '2.2.1', '2.2.2'
+        ]
+      ]
+    ], opt)
+
+    # Check for the dreaded 'content' attribute
+    xml = %q(
+      <opt>
+        <item attr="value">text</item>
+      </opt>)
+
+    opt = XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) });
+    assert_equal({
+      'item' => {
+        'content' => 'text',
+        'attr'    => 'value'
+      }
+    }, opt)
+
+    # And check that we can change its name if required
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'content_key' => 'text_content'
+    })
+    assert_equal({
+      'item' => {
+        'text_content' => 'text',
+        'attr'         => 'value'
+      }
+    }, opt)
+
+    # Check that it doesn't get screwed up by force_array option
+    xml = %q(<opt attr="value">text content</opt>)
+    opt = XmlSimple.xml_in(xml, { 'key_attr' => %w(name key id) })
+    assert_equal({
+      'attr'    => 'value',
+      'content' => 'text content'
+    }, opt)
+
+    # Test that we can force all text content to parse to hash values
+    xml = %q(<opt><x>text1</x><y a="2">text2</y></opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_content' => true,
+      'force_array'   => false,
+      'key_attr'      => %w(name key id)
+    })
+    assert_equal({
+      'x' => {
+        'content' => 'text1'
+      },
+      'y' => {
+        'a'       => '2',
+        'content' => 'text2'
+      }
+    }, opt)
+
+    # And that this is compatible with changing the key name
+    opt = XmlSimple.xml_in(xml, {
+      'force_content' => true,
+      'content_key'   => '0',
+      'force_array'   => false,
+      'key_attr'      => %w(name key id)
+    })
+    assert_equal({
+      'x' => {
+        '0' => 'text1'
+      },
+      'y' => {
+        'a' => '2',
+        '0' => 'text2'
+      }
+    }, opt)
+
+    # Confirm that spurious 'content' key are *not* eliminated
+    # after array folding.
+    xml = %q(<opt><x y="one">First</x><x y="two">Second</x></opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => [ 'x' ],
+      'key_attr'    => { 'x' => 'y' }
+    })
+    assert_equal({
+      'x' => {
+        'one' => { 'content' => 'First' },
+        'two' => { 'content' => 'Second' }
+      }
+    }, opt)
+
+    # unless we ask nicely
+    xml = %q(<opt><x y="one">First</x><x y="two">Second</x></opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => [ 'x' ],
+      'key_attr'    => { 'x' => 'y' },
+      'content_key' => '-content'
+    })
+    assert_equal({
+      'x' => {
+        'one' => 'First',
+        'two' => 'Second'
+      }
+    }, opt)
+    
+    # Check that mixed content parses in the weird way we expect
+    xml = %q(<p class="mixed">Text with a <b>bold</b> word</p>)
+    expected = {
+      'class'   => 'mixed',
+      'content' => [ 'Text with a ', ' word' ],
+      'b'       => 'bold'
+    }
+    assert_equal(expected, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+
+    expected = {
+      'class'   => 'mixed',
+      'content' => [ 'Text with a ', ' word' ],
+      'b'       => ['bold']
+    }
+    assert_equal(expected, XmlSimple.xml_in(xml, { 'key_attr' => %w(name key id) }))
+
+    xml = %q(<p class="mixed">Text without a <b>bold</b></p>)
+    expected = {
+      'class'   => 'mixed',
+      'content' => 'Text without a ',
+      'b'       => 'bold'
+    }
+    assert_equal(expected, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+
+    expected = {
+      'class'   => 'mixed',
+      'content' => 'Text without a ',
+      'b'       => ['bold']
+    }
+    assert_equal(expected, XmlSimple.xml_in(xml, { 'key_attr' => %w(name key id) }))
+
+    # Confirm single nested element rolls up into a scalar attribute value
+    string = %q(
+      <opt>
+        <name>value</name>
+      </opt>)
+    opt = XmlSimple.xml_in(string, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({ 'name' => 'value'}, opt)
+
+    # Unless 'forcearray' option is specified
+    opt = XmlSimple.xml_in(string, { 'key_attr' => %w(name key id) })
+    assert_equal({ 'name' => [ 'value' ] }, opt)
+
+    # Confirm array folding of single nested hash
+    string = %q(
+      <opt>
+        <inner name="one" value="1" />
+      </opt>)
+    opt = XmlSimple.xml_in(string, { 'key_attr' => %w(name key id) })
+    assert_equal({ 'inner' => { 'one' => { 'value' => '1' } } }, opt)
+
+    # But not without forcearray option specified
+    opt = XmlSimple.xml_in(string, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({'inner' => { 'name' => 'one', 'value' => '1' } }, opt)
+
+    # Test advanced features of forcearray
+    xml = %q(
+      <opt zero="0">
+        <one>i</one>
+        <two>ii</two>
+        <three>iii</three>
+        <three>3</three>
+        <three>c</three>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => [ 'two' ],
+      'key_attr'    => %w(name key id)
+    })
+    assert_equal({
+      'zero'  => '0',
+      'one'   => 'i',
+      'two'   => [ 'ii' ],
+      'three' => [ 'iii', '3', 'c' ]
+    }, opt)
+
+    # Test force_array regexes
+    xml = %q(
+      <opt zero="0">
+        <one>i</one>
+        <two>ii</two>
+        <three>iii</three>
+        <four>iv</four>
+        <five>v</five>
+      </opt>
+    )
+    opt = XmlSimple.xml_in(xml, {
+      'key_attr'    => %w(name key id),
+      'force_array' => [ %r(^f), 'two', %r(n) ],
+      'content_key' => '-content'
+    })
+    assert_equal({
+      'zero'  => '0',
+      'one'   => [ 'i' ],
+      'two'   => [ 'ii' ],
+      'three' => 'iii',
+      'four'  => [ 'iv' ],
+      'five'  => [ 'v' ]
+    }, opt)
+    
+    # Same again but a single regexp rather than in an arrayref
+    opt = XmlSimple.xml_in(xml, {
+      'key_attr'    => %w(name key id),
+      'force_array' => /^f|e$/,
+      'content_key' => '-content'
+    })
+    assert_equal({
+      'zero'  => '0',
+      'one'   => [ 'i' ],
+      'two'   => 'ii',
+      'three' => [ 'iii' ],
+      'four'  => [ 'iv' ],
+      'five'  => [ 'v' ]
+    }, opt)
+
+    # Test 'noattr' option
+    xml = %q(
+      <opt name="user" password="foobar">
+        <nest attr="value">text</nest>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'     => true,
+      'force_array' => false,
+      'key_attr'    => %w(name key id)
+    })
+    assert_equal({ 'nest' => 'text' }, opt)
+
+    # And make sure it doesn't screw up array folding 
+    xml = %q{
+      <opt>
+        <item><key>a</key><value>alpha</value></item>
+        <item><key>b</key><value>beta</value></item>
+        <item><key>g</key><value>gamma</value></item>
+      </opt>}
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'     => true,
+      'force_array' => false,
+      'key_attr'    => %w(name key id)
+    })
+    assert_equal({
+      'item' => {
+        'a' => { 'value' => 'alpha' },
+        'b' => { 'value' => 'beta' },
+        'g' => { 'value' => 'gamma' }
+      }
+    }, opt)
+
+    # Confirm empty elements parse to empty hashrefs
+    xml = %q(
+      <body>
+        <name>bob</name>
+        <outer attr="value">
+          <inner1 />
+          <inner2></inner2>
+        </outer>
+      </body>)
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'     => true,
+      'force_array' => false,
+      'key_attr'    => %w(name key id)
+    })
+    assert_equal({
+      'name' => 'bob',
+      'outer' => {
+        'inner1' => {},
+        'inner2' => {}
+      }
+    }, opt)
+
+    # Unless 'suppressempty' is enabled
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'        => true,
+      'suppress_empty' => true,
+      'force_array'    => false,
+      'key_attr'       => %w(name key id)
+    })
+    assert_equal({ 'name' => 'bob', }, opt)
+
+    # Check behaviour when 'suppressempty' is set to nil
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'        => true,
+      'suppress_empty' => nil,
+      'force_array'    => false,
+      'key_attr'       => %w(name key id)
+    })
+    assert_equal({
+       'name' => 'bob',
+      'outer' => {
+          'inner1' => nil,
+        'inner2' => nil
+        }
+       }, opt)
+
+    # Check behaviour when 'suppressempty' is set to to empty string;
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'        => true,
+      'suppress_empty' => '',
+      'force_array'    => false,
+      'key_attr'       => %w(name key id)
+    })
+    assert_equal({
+      'name' => 'bob',
+      'outer' => {
+        'inner1' => '',
+        'inner2' => ''
+      }
+    }, opt)
+
+    # Confirm completely empty XML parses to undef with 'suppressempty'
+    xml = %q(
+      <body>
+        <outer attr="value">
+          <inner1 />
+          <inner2></inner2>
+        </outer>
+      </body>)
+    opt = XmlSimple.xml_in(xml, {
+      'no_attr'        => true,
+      'suppress_empty' => true,
+      'force_array'    => false,
+      'key_attr'       => %w(name key id)
+    })
+    assert_equal(nil, opt)
+
+    # Confirm nothing magical happens with grouped elements
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir>/usr/bin</dir>
+          <dir>/usr/local/bin</dir>
+        </dirs>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => false,
+      'key_attr'    => %w(name key id)
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => {
+        'dir' => [ '/usr/bin', '/usr/local/bin' ]
+      },
+      'suffix' => 'after'
+    }, opt)
+    
+    # unless we specify how the grouping works
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir>/usr/bin</dir>
+          <dir>/usr/local/bin</dir>
+        </dirs>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'grouptags'   => { 'dirs' => 'dir' }
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => [ '/usr/bin', '/usr/local/bin' ],
+      'suffix' => 'after'
+    }, opt)
+
+    # Try again with multiple groupings
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir>/usr/bin</dir>
+          <dir>/usr/local/bin</dir>
+        </dirs>
+        <infix>between</infix>
+        <terms>
+          <term>vt100</term>
+          <term>xterm</term>
+        </terms>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'grouptags'   => { 'dirs' => 'dir', 'terms' => 'term' }
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => [ '/usr/bin', '/usr/local/bin' ],
+      'infix'  => 'between',
+      'terms'  => [ 'vt100', 'xterm' ],
+      'suffix' => 'after'
+    }, opt)
+
+    # confirm folding and ungrouping work together
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir name="first">/usr/bin</dir>
+          <dir name="second">/usr/local/bin</dir>
+        </dirs>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array' => false,
+      'key_attr'    => { 'dir' => 'name' },
+      'grouptags'   => { 'dirs' => 'dir' }
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => {
+        'first'  => { 'content' => '/usr/bin' },
+        'second' => { 'content' => '/usr/local/bin' }
+      },
+      'suffix' => 'after'
+    }, opt)
+
+    # confirm folding, ungrouping and content stripping work together
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir name="first">/usr/bin</dir>
+          <dir name="second">/usr/local/bin</dir>
+        </dirs>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-text',
+      'force_array' => false,
+      'key_attr'    => { 'dir' => 'name' },
+      'grouptags'   => { 'dirs' => 'dir' }
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => {
+        'first'  => '/usr/bin',
+        'second' => '/usr/local/bin'
+      },
+      'suffix' => 'after'
+    }, opt)
+
+    # confirm folding fails as expected even with ungrouping
+    # but (no forcearray)
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir name="first">/usr/bin</dir>
+        </dirs>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-text',
+      'force_array' => false,
+      'key_attr'    => { 'dir' => 'name' },
+      'grouptags'   => { 'dirs' => 'dir' }
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => {
+        'name'  => 'first',
+        'text' => '/usr/bin'
+      },
+      'suffix' => 'after'
+    }, opt)
+
+    # but works with force_array enabled
+    xml = %q(
+      <opt>
+        <prefix>before</prefix>
+        <dirs>
+          <dir name="first">/usr/bin</dir>
+        </dirs>
+        <suffix>after</suffix>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-text',
+      'force_array' => [ 'dir' ],
+      'key_attr'    => { 'dir' => 'name' },
+      'grouptags'   => { 'dirs' => 'dir' }
+    })
+    assert_equal({
+      'prefix' => 'before',
+      'dirs'   => { 'first' => '/usr/bin' },
+      'suffix' => 'after'
+    }, opt)
+
+    # Test variable expansion - when no variables are defined
+    xml = %q(
+      <opt>
+        <file name="config_file">${conf_dir}/appname.conf</file>
+        <file name="log_file">${log_dir}/appname.log</file>
+        <file name="debug_file">${log_dir}/appname.dbg</file>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-content',
+      'force_array' => false,
+      'key_attr'    => %w(name key id)
+    })
+    assert_equal({
+      'file' => {
+        'config_file' => '${conf_dir}/appname.conf',
+        'log_file'    => '${log_dir}/appname.log',
+        'debug_file'  => '${log_dir}/appname.dbg'
+      }
+    }, opt)
+
+    # try again but with variables defined in advance
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-content',
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'variables'   => { 'conf_dir' => '/etc', 'log_dir' => '/var/log' }
+    })
+    assert_equal({
+      'file' => {
+        'config_file' => '/etc/appname.conf',
+        'log_file'    => '/var/log/appname.log',
+        'debug_file'  => '/var/log/appname.dbg'
+      }
+    }, opt)
+
+    # now try defining them in the XML
+    xml = %q(
+      <opt>
+        <dir xsvar="conf_dir">/etc</dir>
+        <dir xsvar="log_dir">/var/log</dir>
+        <file name="config_file">${conf_dir}/appname.conf</file>
+        <file name="log_file">${log_dir}/appname.log</file>
+        <file name="debug_file">${log_dir}/appname.dbg</file>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-content',
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'varattr'     => 'xsvar'
+    })
+    assert_equal({
+      'file' => {
+        'config_file' => '/etc/appname.conf',
+        'log_file'    => '/var/log/appname.log',
+        'debug_file'  => '/var/log/appname.dbg'
+      },
+      'dir'  => [
+        { 'xsvar' => 'conf_dir', 'content' => '/etc' },
+        { 'xsvar' => 'log_dir',  'content' => '/var/log' }
+      ]
+    }, opt)
+
+    # confirm that variables in XML are merged with pre-defined ones
+    xml = %q(
+      <opt>
+        <dir xsvar="log_dir">/var/log</dir>
+        <file name="config_file">${conf_dir}/appname.conf</file>
+        <file name="log_file">${log_dir}/appname.log</file>
+        <file name="debug_file">${log_dir}/appname.dbg</file>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-content',
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'varattr'     => 'xsvar',
+      'variables'   => { 'conf_dir' => '/etc', 'log_dir' => '/tmp' }
+    })
+    assert_equal({
+      'file' => {
+        'config_file' => '/etc/appname.conf',
+        'log_file'    => '/var/log/appname.log',
+        'debug_file'  => '/var/log/appname.dbg'
+      },
+      'dir' => { 'xsvar' => 'log_dir',  'content' => '/var/log' }
+    }, opt)
+
+    # confirm that variables are expanded in variable definitions
+    xml = %q(
+      <opt>
+        <dirs>
+          <dir name="prefix">/usr/local/apache</dir>
+          <dir name="exec_prefix">${prefix}</dir>
+          <dir name="bin_dir">${exec_prefix}/bin</dir>
+        </dirs>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'content_key' => '-content',
+      'force_array' => false,
+      'key_attr'    => %w(name key id),
+      'varattr'     => 'name',
+      'grouptags'   => { 'dirs' => 'dir' }
+    })
+    assert_equal({
+      'dirs' => {
+        'prefix'      => '/usr/local/apache',
+        'exec_prefix' => '/usr/local/apache',
+        'bin_dir'     => '/usr/local/apache/bin'
+      }
+    }, opt)
+
+    # Test option error handling
+    assert_raises(ArgumentError) {
+      XmlSimple.xml_in('<x y="z" />', { 'root_name' => 'fred' })
+    }
+
+    # Test the NormaliseSpace option
+    xml = %q(
+      <opt>
+        <user name="  Joe
+        Bloggs  " id="  one  two "/>
+        <user>
+          <name>  Jane
+          Doe </name>
+          <id>
+          three
+          four
+          </id>
+        </user>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array'    => false,
+      'key_attr'       => %w(name),
+      'NormaliseSpace' => 1
+    })
+    assert(opt['user'].instance_of?(Hash))
+    assert(opt['user'].has_key?('Joe Bloggs'))
+    assert(opt['user'].has_key?('Jane Doe'))
+    assert(opt['user']['Jane Doe']['id'] =~ /^\s\s+three\s\s+four\s\s+$/s)
+
+    opt = XmlSimple.xml_in(xml, {
+      'force_array'    => false,
+      'key_attr'       => %w(name),
+      'NormaliseSpace' => 2
+    })
+    assert(opt['user'].instance_of?(Hash))
+    assert(opt['user'].has_key?('Joe Bloggs'))
+    assert(opt['user']['Joe Bloggs']['id'] =~ /^one\stwo$$/s)
+    assert(opt['user'].has_key?('Jane Doe'))
+    assert(opt['user']['Jane Doe']['id'] =~ /^three\sfour$/s)
+
+    # confirm NormaliseSpace works in anonymous arrays too
+    xml = %q(
+      <opt>
+        <anon>  one  two </anon><anon> three
+        four  five </anon><anon> six </anon><anon> seveneightnine </anon>
+      </opt>)
+    opt = XmlSimple.xml_in(xml, {
+      'force_array'    => false,
+      'key_attr'       => %w(name key id),
+      'NormaliseSpace' => 2
+    })
+    assert_equal([
+      'one two', 'three four five', 'six', 'seveneightnine'
+    ], opt)
+
+    # Check that American speeling works too
+    opt = XmlSimple.xml_in(xml, {
+      'force_array'    => false,
+      'key_attr'       => %w(name key id),
+      'NormalizeSpace' => 2
+    })
+    assert_equal([
+      'one two', 'three four five', 'six', 'seveneightnine'
+    ], opt)
+
+    # Now for a 'real world' test, try slurping in an SRT config file
+    opt = XmlSimple.xml_in(File.join(File.dirname(__FILE__), 'files', 'srt.xml'), { 'key_attr' => %w(name key id) })
+    target = {
+      'global' => [
+        {
+          'proxypswd' => 'bar',
+          'proxyuser' => 'foo',
+          'exclude' => [
+            '/_vt',
+            '/save\\b',
+            '\\.bak$',
+            '\\.\\$\\$\\$$'
+          ],
+          'httpproxy' => 'http://10.1.1.5:8080/',
+          'tempdir' => 'C:/Temp'
+        }
+      ],
+      'pubpath' => {
+        'test1' => {
+          'source' => [
+            {
+              'label' => 'web_source',
+              'root' => 'C:/webshare/web_source'
+            }
+          ],
+          'title' => 'web_source -> web_target1',
+          'package' => {
+            'images' => { 'dir' => 'wwwroot/images' }
+          },
+          'target' => [
+            {
+              'label' => 'web_target1',
+              'root' => 'C:/webshare/web_target1',
+              'temp' => 'C:/webshare/web_target1/temp'
+            }
+          ],
+          'dir' => [ 'wwwroot' ]
+        },
+        'test2' => {
+          'source' => [
+            {
+              'label' => 'web_source',
+              'root' => 'C:/webshare/web_source'
+            }
+          ],
+          'title' => 'web_source -> web_target1 & web_target2',
+          'package' => {
+            'bios' => { 'dir' => 'wwwroot/staff/bios' },
+            'images' => { 'dir' => 'wwwroot/images' },
+            'templates' => { 'dir' => 'wwwroot/templates' }
+          },
+          'target' => [
+            {
+              'label' => 'web_target1',
+              'root' => 'C:/webshare/web_target1',
+              'temp' => 'C:/webshare/web_target1/temp'
+            },
+            {
+              'label' => 'web_target2',
+              'root' => 'C:/webshare/web_target2',
+              'temp' => 'C:/webshare/web_target2/temp'
+            }
+          ],
+          'dir' => [ 'wwwroot' ]
+        },
+        'test3' => {
+          'source' => [
+            {
+              'label' => 'web_source',
+              'root' => 'C:/webshare/web_source'
+            }
+          ],
+          'title' => 'web_source -> web_target1 via HTTP',
+          'addexclude' => [ '\\.pdf$' ],
+          'target' => [
+            {
+              'label' => 'web_target1',
+              'root' => 'http://127.0.0.1/cgi-bin/srt_slave.plx',
+              'noproxy' => '1'
+            }
+          ],
+          'dir' => [ 'wwwroot' ]
+        }
+      }
+    }
+    assert_equal(target, opt)
+
+  end
+end
+
diff --git a/test/tc_perl_in.xml b/test/tc_perl_in.xml
new file mode 100755
index 0000000..016d52f
--- /dev/null
+++ b/test/tc_perl_in.xml
@@ -0,0 +1 @@
+<opt location="tc_perl_in.xml" />
diff --git a/test/tc_perl_mem_copy.rb b/test/tc_perl_mem_copy.rb
new file mode 100755
index 0000000..5b23595
--- /dev/null
+++ b/test/tc_perl_mem_copy.rb
@@ -0,0 +1,101 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+require 'fileutils'
+
+# The test cases below are copied from the original Perl version,
+# because I wanted to behave the Ruby version exactly as the Perl
+# version. I left some comments, that maybe do not make a lot of
+# sense in the current Ruby version just to make it easier to find
+# changes between the current and future Perl versions of the
+# module.
+# Please note, that a major difference between the Perl and the Ruby
+# version is, that the defaults of the options 'force_array' and
+# 'key_attr' have changed.
+class TC_Perl_Mem_Copy < Test::Unit::TestCase # :nodoc:
+  # Wait until the current time is greater than the supplied value
+  def pass_time(target)
+    while Time::now.to_i <= target
+      sleep 1
+    end
+  end
+  
+  def test_perl_test_cases
+    src_file = File.join(File.dirname(__FILE__), 'files', 'desertnet.src')
+    xml_file = File.join(File.dirname(__FILE__), 'files', 'desertnet.xml')
+    raise "Test data is missing!" unless File::exist?(src_file)
+
+    # Make sure we can write to the filesystem and check it uses the same
+    # clock as the machine we're running on.
+    t0   = Time::now.to_i
+    file = File.open(xml_file, "w")
+    file.close
+    t1   = File::mtime(xml_file).to_i
+    t2   = Time::now.to_i
+    raise "Time moved backwards!" if (t1 < t0) || (t2 < t1)
+
+    # Initialise test data
+    expected  = {
+      'server' => {
+        'sahara' => {
+          'osversion' => '2.6',
+          'osname'    => 'solaris',
+          'address'   => [
+            '10.0.0.101',
+            '10.0.1.101'
+          ]
+        },
+        'gobi' => {
+          'osversion' => '6.5',
+          'osname'    => 'irix',
+          'address'   => '10.0.0.102'
+        },
+        'kalahari' => {
+          'osversion' => '2.0.34',
+          'osname'    => 'linux',
+          'address'   => [
+            '10.0.0.103',
+            '10.0.1.103'
+          ]
+        }
+      }
+    }
+
+    FileUtils.cp(src_file, xml_file)
+    t0 = File::mtime(xml_file)
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_copy' })
+    assert_equal(expected, opt)
+
+    FileUtils.rm(xml_file)
+    assert(!File::exist?(xml_file))
+    file = File.open(xml_file, "w") # Re-create it (empty)
+    file.close
+    assert(File::exist?(xml_file))
+    t1 = t0 - 1
+    File.utime(t1, t1, xml_file)
+    t2 = File::mtime(xml_file)
+    if (t2 < t0)
+      opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_copy' })
+      assert_equal(expected, opt)
+      assert_equal(File::size(xml_file), 0)
+    else
+      puts "No utime!"
+    end
+    pass_time(Time::now().to_i)
+
+    # Write some new data to the XML file
+    File.open(xml_file, "w") { |f| f.write('<opt one="1" two="2"></opt>' + "\n") }
+    # Ensure current time later than file time.
+    pass_time(Time::now().to_i)
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_copy' })
+    assert_equal({ 'one' => '1', 'two' => '2' }, opt)
+    opt['three'] = 3 # Alter the returned structure and retrieve again from cache
+    opt2 = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_copy' })
+    assert_equal(nil, opt2['three'])
+
+    # Clean up.
+    FileUtils.rm(xml_file)
+  end
+end
+
diff --git a/test/tc_perl_mem_share.rb b/test/tc_perl_mem_share.rb
new file mode 100755
index 0000000..7715669
--- /dev/null
+++ b/test/tc_perl_mem_share.rb
@@ -0,0 +1,100 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+require 'fileutils'
+
+# The test cases below are copied from the original Perl version,
+# because I wanted to behave the Ruby version exactly as the Perl
+# version. I left some comments, that maybe do not make a lot of
+# sense in the current Ruby version just to make it easier to find
+# changes between the current and future Perl versions of the
+# module.
+# Please note, that a major difference between the Perl and the Ruby
+# version is, that the defaults of the options 'force_array' and
+# 'key_attr' have changed.
+class TC_Perl_Mem_Share < Test::Unit::TestCase # :nodoc:
+  # Wait until the current time is greater than the supplied value
+  def pass_time(target)
+    while Time::now.to_i <= target
+      sleep 1
+    end
+  end
+  
+  def test_perl_test_cases
+    src_file = File.join(File.dirname(__FILE__), 'files', 'desertnet.src')
+    xml_file = File.join(File.dirname(__FILE__), 'files', 'desertnet.xml')
+    raise "Test data is missing!" unless File::exist?(src_file)
+
+    # Make sure we can write to the filesystem and check it uses the same
+    # clock as the machine we're running on.
+    t0   = Time::now.to_i
+    file = File.open(xml_file, "w")
+    file.close
+    t1   = File::mtime(xml_file).to_i
+    t2   = Time::now.to_i
+    raise "Time moved backwards!" if (t1 < t0) || (t2 < t1)
+
+    # Initialise test data
+    expected  = {
+      'server' => {
+        'sahara' => {
+          'osversion' => '2.6',
+          'osname'    => 'solaris',
+          'address'   => [
+            '10.0.0.101',
+            '10.0.1.101'
+          ]
+        },
+        'gobi' => {
+          'osversion' => '6.5',
+          'osname'    => 'irix',
+          'address'   => '10.0.0.102'
+        },
+        'kalahari' => {
+          'osversion' => '2.0.34',
+          'osname'    => 'linux',
+          'address'   => [
+            '10.0.0.103',
+            '10.0.1.103'
+          ]
+        }
+      }
+    }
+
+    FileUtils.cp(src_file, xml_file)
+    t0 = File::mtime(xml_file)
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_share' })
+    assert_equal(expected, opt)
+
+    FileUtils.rm(xml_file)
+    assert(!File::exist?(xml_file))
+    file = File.open(xml_file, "w") # Re-create it (empty)
+    file.close
+    assert(File::exist?(xml_file))
+    t1 = t0 - 1
+    File.utime(t1, t1, xml_file)
+    t2 = File::mtime(xml_file)
+    if (t2 < t0)
+      opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_share' })
+      assert_equal(expected, opt)
+      assert_equal(File::size(xml_file), 0)
+    else
+      puts "No utime!"
+    end
+    pass_time(Time::now().to_i)
+
+    # Write some new data to the XML file
+    File.open(xml_file, "w") { |f| f.write('<opt one="1" two="2"></opt>' + "\n") }
+    # Ensure current time later than file time.
+    pass_time(Time::now().to_i)
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_share' })
+    assert_equal({ 'one' => '1', 'two' => '2' }, opt)
+    opt['three'] = 3 # Alter the returned structure and retrieve again from cache
+    opt2 = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'mem_share' })
+    assert_equal(3, opt2['three'])
+
+    # Clean up.
+    FileUtils.rm(xml_file)
+  end
+end
diff --git a/test/tc_perl_out.rb b/test/tc_perl_out.rb
new file mode 100755
index 0000000..067773f
--- /dev/null
+++ b/test/tc_perl_out.rb
@@ -0,0 +1,789 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+# The test cases below are copied from the original Perl version,
+# because I wanted to behave the Ruby version exactly as the Perl
+# version. I left some comments, that maybe do not make a lot of
+# sense in the current Ruby version just to make it easier to find
+# changes between the current and future Perl versions of the
+# module.
+# Please note, that a major difference between the Perl and the Ruby
+# version is, that the defaults of the options 'force_array' and
+# 'key_attr' have changed.
+class TC_Perl_Out < Test::Unit::TestCase # :nodoc:
+  def test_perl_test_cases
+    # Try encoding a scalar value
+    xml = XmlSimple.xml_out("scalar", { 'key_attr' => %w(name key id) });
+    assert_equal('<opt>scalar</opt>', xml.strip)
+    assert_equal('scalar', XmlSimple.xml_in(xml))
+
+    # Next try encoding a hash
+    hashref1 = { 'one' => 1, 'two' => 'II', 'three' => '...' }
+    hashref2 = { 'one' => 1, 'two' => 'II', 'three' => '...' }
+
+    xml = XmlSimple.xml_out(hashref1)
+    parts = xml.strip.split(' ').sort
+    assert_equal(['/>', '<opt', 'one="1"', 'three="..."', 'two="II"'], parts)
+    assert_equal({ 'one' => '1', 'two' => 'II', 'three' => '...' }, XmlSimple.xml_in(xml))
+
+    # Now try encoding a hash with a nested array
+    ref = { 'array' => %w(one two three) }
+
+    # Expect:
+    # <opt>
+    #   <array>one</array>
+    #   <array>two</array>
+    #   <array>three</array>
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert(
+      xml =~ %r!<array>one</array>\s*
+         <array>two</array>\s*
+         <array>three</array>!sx)
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+
+    # Now try encoding a nested hash
+    ref = {
+      'value' => '555 1234',
+      'hash1' => { 'one' => 1 },
+      'hash2' => { 'two' => 2 }
+    }
+
+    # Expect:
+    # <opt value="555 1234">
+    #   <hash1 one="1" />
+    #   <hash2 two="2" />
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal({
+      'hash1' => { 'one' => '1' },
+      'hash2' => { 'two' => '2' },
+      'value' => '555 1234'
+    }, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(xml =~ %r!<hash1 one="1" />\s*!s)
+    assert(xml =~ %r!<hash2 two="2" />\s*!s)
+
+    # Now try encoding an anonymous array
+    ref = %w(1 two III)
+    
+    # Expect:
+    # <opt>
+    #   <anon>1</anon>
+    #   <anon>two</anon>
+    #   <anon>III</anon>
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(xml =~ %r{
+      ^<(\w+)\s*>
+      \s*<anon>1</anon>
+      \s*<anon>two</anon>
+      \s*<anon>III</anon>
+      \s*</\1>\s*$}sx)
+
+    # Now try encoding a nested anonymous array
+    ref = [ %w(1.1 1.2), %w(2.1 2.2) ]
+
+    # Expect:
+    # <opt>
+    #   <anon>
+    #     <anon>1.1</anon>
+    #     <anon>1.2</anon>
+    #   </anon>
+    #   <anon>
+    #     <anon>2.1</anon>
+    #     <anon>2.2</anon>
+    #   </anon>
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(xml =~ %r{
+      <(\w+)\s*>
+      \s*<anon\s*>
+      \s*<anon\s*>1\.1</anon\s*>
+      \s*<anon\s*>1\.2</anon\s*>
+      \s*</anon\s*>
+      \s*<anon\s*>
+      \s*<anon\s*>2\.1</anon\s*>
+      \s*<anon\s*>2\.2</anon\s*>
+      \s*</anon\s*>
+      \s*</\1\s*>}sx)
+
+    # Now try encoding a hash of hashes with key folding disabled
+    ref = {
+      'country' => {
+        'England' => { 'capital' => 'London' },
+        'France'  => { 'capital' => 'Paris' },
+        'Turkey'  => { 'capital' => 'Istanbul' }
+      }
+    }
+
+    # Expect:
+    # <opt>
+    #   <country>
+    #     <England capital="London" />
+    #     <France capital="Paris" />
+    #     <Turkey capital="Istanbul" />
+    #   </country>
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => [] })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    e_doc = REXML::Document.new(xml)
+    assert_equal(e_doc.root.name, 'opt')
+    [%w(England London), %w(France Paris), %w(Turkey Istanbul)].each do |country, capital|
+      assert_equal(e_doc.root.elements["/opt/country/#{country}/@capital"].value, capital)
+    end
+
+    # Try encoding same again with key folding set to non-standard value
+    # Expect:
+    # <opt>
+    #   <country fullname="England" capital="London" />
+    #   <country fullname="France" capital="Paris" />
+    #   <country fullname="Turkey" capital="Istanbul" />
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => ['fullname'] })
+    xml_save = xml.dup
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(fullname) }))
+    assert(!xml.sub!(%r!\s*fullname="England"!s, 'uk').nil?)
+    assert(!xml.sub!(%r!\s*capital="London"!s, 'uk').nil?)
+    assert(!xml.sub!(%r!\s*fullname="France"!s, 'fr').nil?)
+    assert(!xml.sub!(%r!\s*capital="Paris"!s, 'fr').nil?)
+    assert(!xml.sub!(%r!\s*fullname="Turkey"!s, 'tk').nil?)
+    assert(!xml.sub!(%r!\s*capital="Istanbul"!s, 'tk').nil?)
+    assert(!xml.sub!(%r!<countryukuk\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<countryfrfr\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<countrytktk\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>\s*</\1>$!s, '').nil?)
+
+    # Same again but specify name as scalar rather than array
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => 'fullname' })
+    assert_equal(xml_save, xml)
+
+    # Same again but specify keyattr as hash rather than array
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => { 'country' => 'fullname' }})
+    assert_equal(xml_save, xml)
+
+    # Same again but add leading '+'
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => { 'country' => '+fullname' }})
+    assert_equal(xml_save, xml)
+
+    # and leading '-'
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => { 'country' => '-fullname' }})
+    assert_equal(xml_save, xml)
+
+    # One more time but with default key folding values
+
+    # Expect:
+    # <opt>
+    #   <country name="England" capital="London" />
+    #   <country name="France" capital="Paris" />
+    #   <country name="Turkey" capital="Istanbul" />
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!\s*name="England"!s, 'uk').nil?)
+    assert(!xml.sub!(%r!\s*capital="London"!s, 'uk').nil?)
+    assert(!xml.sub!(%r!\s*name="France"!s, 'fr').nil?)
+    assert(!xml.sub!(%r!\s*capital="Paris"!s, 'fr').nil?)
+    assert(!xml.sub!(%r!\s*name="Turkey"!s, 'tk').nil?)
+    assert(!xml.sub!(%r!\s*capital="Istanbul"!s, 'tk').nil?)
+    assert(!xml.sub!(%r!<countryukuk\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<countryfrfr\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<countrytktk\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>\s*</\1>$!s, '').nil?)
+
+    # Finally, confirm folding still works with only one nested hash
+
+    # Expect:
+    # <opt>
+    #   <country name="England" capital="London" />
+    # </opt>
+    ref = { 'country' => { 'England' => { 'capital' => 'London' } } }
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!\s*name="England"!s, 'uk').nil?)
+    assert(!xml.sub!(%r!\s*capital="London"!s, 'uk').nil?)
+    assert(!xml.sub!(%r!<countryukuk\s*/>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>\s*</\1>$!s, '').nil?)
+
+    # Check that default XML declaration works
+    #
+    # Expect:
+    # <?xml version='1.0' standalone='yes'?>
+    # <opt one="1" />
+    ref = { 'one' => 1 }
+    xml = XmlSimple.xml_out(ref, { 'xml_declaration' => true, 'key_attr' => %w(name key id) })
+    assert_equal({ 'one' => '1' }, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!<\?xml version='1.0' standalone='yes'\?>!s, '').nil?)
+    assert(xml =~ /^\s*<opt\s+one="1"\s*\/>/s)
+
+    # Check that custom XML declaration works
+    #
+    # Expect:
+    # <?xml version='1.0' standalone='yes'?>
+    # <opt one="1" />
+    xml = XmlSimple.xml_out(ref, { 'xml_declaration' => "<?xml version='1.0' standalone='yes'?>", 'key_attr' => %w(name key id)})
+    assert_equal({ 'one' => '1' }, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!<\?xml version='1.0' standalone='yes'\?>!s, '').nil?)
+    assert(xml =~ /^\s*<opt\s+one="1"\s*\/>/s)
+
+    # Check that special characters do get escaped
+    ref = { 'a' => '<A>', 'b' => '"B"', 'c' => '&C&', 'd' => "'D'" }
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!a="&lt;A&gt;"!s, '').nil?)
+    assert(!xml.sub!(%r!b="&quot;B&quot;"!s, '').nil?)
+    assert(!xml.sub!(%r!c="&amp;C&amp;"!s, '').nil?)
+    assert(!xml.sub!(%r!d="&apos;D&apos;"!s, '').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*/>$!s, '').nil?)
+
+    # unless we turn escaping off
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id), 'no_escape' => true })
+    assert(!xml.sub!(%r!a="<A>"!s, '').nil?)
+    assert(!xml.sub!(%r!b=""B""!s, '').nil?)
+    assert(!xml.sub!(%r!c="&C&"!s, '').nil?)
+    assert(!xml.sub!(%r!d="'D'"!s, '').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*/>$!s, '').nil?)
+
+    # Try encoding a circular data structure and confirm that it fails
+    ref = { 'a' => '1' }
+    ref['b'] = ref
+    assert_raises(ArgumentError) { XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) }) }
+
+    # Try encoding a repetitive (but non-circular) data structure and confirm that 
+    # it does not fail
+    a   = { 'alpha' => '1' }
+    ref = { 'a' => a, 'b' => a }
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert(xml =~ %r!^
+      <opt>
+      \s*<a\s+alpha="1"\s*/>
+      \s*<b\s+alpha="1"\s*/>
+      \s*</opt>!xs)
+
+    # Perl comment: "Try encoding a blessed reference and
+    #                confirm that it fails".
+    # That isn't true for the Ruby version, because every
+    # object has a to_s method.
+    ref = Time::now
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert_equal(xml, "<opt>#{ref}</opt>\n")
+
+    # Repeat some of the above tests with named root element
+
+    # Try encoding a scalar value
+    xml = XmlSimple.xml_out("scalar", { 'root_name' => 'TOM', 'key_attr' => %w(name key id) });
+    assert_equal('scalar', XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(xml =~ %r/^\s*<TOM>scalar<\/TOM>\s*$/si)
+
+    # Next try encoding a hash
+
+    # Expect:
+    # <DICK one="1" two="II" three="..." />
+    xml = XmlSimple.xml_out(hashref1, { 'root_name' => 'DICK', 'key_attr' => %w(name key id) })
+    assert_equal({
+      'one' => '1',
+      'two' => 'II',
+      'three' => '...'
+    }, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+
+    assert(!xml.sub!(%r/one="1"/s, '').nil?)
+    assert(!xml.sub!(%r/two="II"/s, '').nil?)
+    assert(!xml.sub!(%r/three="..."/s, '').nil?)
+    assert(!xml.sub!(%r/^<DICK\s+\/>/s, '').nil?)
+
+    # Now try encoding a hash with a nested array
+    ref = { 'array' => %w(one two three) }
+
+    # Expect:
+    # <LARRY>
+    #   <array>one</array>
+    #   <array>two</array>
+    #   <array>three</array>
+    # </LARRY>
+    xml = XmlSimple.xml_out(ref, { 'root_name' => 'LARRY', 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!
+      <array>one</array>\s*
+      <array>two</array>\s*
+      <array>three</array>!sx, '').nil?)
+    assert(!xml.sub!(%r/^<(LARRY)\s*>\s*<\/\1>\s*$/s, '').nil?)
+
+    # Now try encoding a nested hash
+    ref = {
+      'value' => '555 1234',
+      'hash1' => { 'one' => '1' },
+      'hash2' => { 'two' => '2' }
+    }
+
+    # Expect:
+    # <CURLY value="555 1234">
+    #   <hash1 one="1" />
+    #   <hash2 two="2" />
+    # </CURLY>
+    xml = XmlSimple.xml_out(ref, { 'root_name' => 'CURLY', 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!<hash1 one="1" />\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<hash2 two="2" />\s*!s, '').nil?)
+    assert(!xml.sub!(%r!^<(CURLY)\s+value="555 1234"\s*>\s*</\1>\s*$!s, '').nil?)
+
+    # Now try encoding an anonymous array
+    ref = %w(1 two III)
+
+    # Expect:
+    # <MOE>
+    #   <anon>1</anon>
+    #   <anon>two</anon>
+    #   <anon>III</anon>
+    # </MOE>
+    xml = XmlSimple.xml_out(ref, { 'root_name' => 'MOE', 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!
+      ^<(MOE)\s*>
+      \s*<anon>1</anon>
+      \s*<anon>two</anon>
+      \s*<anon>III</anon>
+      \s*</\1>\s*$!sx, '').nil?)
+
+    # Test again, this time with no root element
+
+    # Try encoding a scalar value
+    xml = XmlSimple.xml_out("scalar", { 'root_name' => '', 'key_attr' => %w(name key id) });
+    assert(xml =~ /scalar\s+/s)
+    xml = XmlSimple.xml_out("scalar", { 'root_name' => nil, 'key_attr' => %w(name key id) });
+    assert(xml =~ /scalar\s+/s)
+
+    # Next try encoding a hash
+
+    # Expect:
+    #   <one>1</one>
+    #   <two>II</two>
+    #   <three>...</three>
+    xml = XmlSimple.xml_out(hashref1, { 'root_name' => '', 'key_attr' => %w(name key id) })
+    assert_equal({
+      'one' => '1',
+      'two' => 'II',
+      'three' => '...'
+    }, XmlSimple.xml_in("<opt>" + xml + "</opt>", { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r/<one>1<\/one>/, '').nil?)
+    assert(!xml.sub!(%r/<two>II<\/two>/, '').nil?)
+    assert(!xml.sub!(%r/<three>...<\/three>/, '').nil?)
+    assert(!xml.sub!(%r/^\s*$/, '').nil?)
+
+    # Now try encoding a nested hash
+    ref = {
+      'value' => '555 1234',
+      'hash1' => { 'one' => '1' },
+      'hash2' => { 'two' => '2' }
+    }
+
+    # Expect:
+    #   <value>555 1234</value>
+    #   <hash1 one="1" />
+    #   <hash2 two="2" />
+    xml = XmlSimple.xml_out(ref, { 'root_name' => '', 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in("<opt>" + xml + "</opt>", { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!<value>555 1234<\/value>\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<hash1 one="1" />\s*!s, '').nil?)
+    assert(!xml.sub!(%r!<hash2 two="2" />\s*!s, '').nil?)
+    assert(!xml.sub!(%r!^\s*$!s, '').nil?)
+
+    # Now try encoding an anonymous array
+    ref = %w(1 two III)
+
+    # Expect:
+    #   <anon>1</anon>
+    #   <anon>two</anon>
+    #   <anon>III</anon>
+    xml = XmlSimple.xml_out(ref, { 'root_name' => '', 'key_attr' => %w(name key id) })
+    assert_equal(ref, XmlSimple.xml_in("<opt>" + xml + "</opt>", { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!
+      ^\s*<anon>1</anon>
+      \s*<anon>two</anon>
+      \s*<anon>III</anon>
+      \s*$!sx, '').nil?)
+
+    # Test option error handling
+    assert_raises(ArgumentError) { XmlSimple.xml_out(hashref1, { 'search_path' => [] })} # only valid for XmlSimple.xml_in()
+    assert_raises(ArgumentError) { XmlSimple.xml_out(hashref1, 'bogus') }
+
+    # Test output to file
+    test_file = 'testoutput.xml'
+    File.delete(test_file) if File.exist?(test_file)
+    assert(!File.exist?(test_file))
+
+    xml = XmlSimple.xml_out(hashref1)
+    XmlSimple.xml_out(hashref1, { 'output_file' => test_file })
+    assert(File.exist?(test_file))
+    assert_equal(xml, IO::read(test_file))
+    File.delete(test_file)
+
+    # Test output to an IO handle
+    assert(!File.exist?(test_file))
+    fh = File.open(test_file, "w")
+    XmlSimple.xml_out(hashref1, { 'output_file' => fh })
+    fh.close()
+    assert(File.exist?(test_file))
+    assert_equal(xml, IO::read(test_file))
+    File.delete(test_file)
+
+    # After all that, confirm that the original hashref we supplied has not
+    # been corrupted.
+    assert_equal(hashref1, hashref2)
+
+    # Confirm that hash keys with leading '-' are skipped
+    ref = {
+      'a'  => 'one',
+      '-b' => 'two',
+      '-c' => {
+        'one' => '1',
+        'two' => '2'
+      }
+    }
+    xml = XmlSimple.xml_out(ref, { 'root_name' => 'opt', 'key_attr' => %w(name key id) })
+    assert(!xml.sub!(%r!^\s*<opt\s+a="one"\s*/>\s*$!s, '').nil?)
+
+    # Try a more complex unfolding with key attributes named in a hash
+    ref = {
+      'car' => {
+        'LW1804' => {
+          'option' => {
+            '9926543-1167' => {
+              'key'  => '1',
+              'desc' => 'Steering Wheel'
+            }
+          },
+          'id'   => '2',
+          'make' => 'GM'
+        },
+        'SH6673' => {
+          'option' => {
+            '6389733317-12' => {
+              'key'  => '2', 
+              'desc' => 'Electric Windows'
+            },
+            '3735498158-01' => {
+              'key'  => '3',
+              'desc' => 'Leather Seats'
+            },
+            '5776155953-25' => {
+              'key'  => '4',
+              'desc' => 'Sun Roof'
+            }
+          },
+          'id'   => '1',
+          'make' => 'Ford'
+        }
+      }
+    }
+
+    # Expect:
+    # <opt>
+    #   <car license="LW1804" id="2" make="GM">
+    #     <option key="1" pn="9926543-1167" desc="Steering Wheel" />
+    #   </car>
+    #   <car license="SH6673" id="1" make="Ford">
+    #     <option key="2" pn="6389733317-12" desc="Electric Windows" />
+    #     <option key="3" pn="3735498158-01" desc="Leather Seats" />
+    #     <option key="4" pn="5776155953-25" desc="Sun Roof" />
+    #   </car>
+    # </opt>
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => { 'car' => 'license', 'option' => 'pn' }})
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'key_attr' =>  { 'car' => 'license', 'option' => 'pn' }}))
+    assert(!xml.sub!(%r!\s*make="GM"!s, 'gm').nil?)
+    assert(!xml.sub!(%r!\s*id="2"!s, 'gm').nil?)
+    assert(!xml.sub!(%r!\s*license="LW1804"!s, 'gm').nil?)
+    assert(!xml.sub!(%r!\s*desc="Steering Wheel"!s, 'opt').nil?)
+    assert(!xml.sub!(%r!\s*pn="9926543-1167"!s, 'opt').nil?)
+    assert(!xml.sub!(%r!\s*key="1"!s, 'opt').nil?)
+    assert(!xml.sub!(%r!\s*<cargmgmgm>\s*<optionoptoptopt\s*/>\s*</car>!s, 'CAR').nil?)
+    assert(!xml.sub!(%r!\s*make="Ford"!s, 'ford').nil?)
+    assert(!xml.sub!(%r!\s*id="1"!s, 'ford').nil?)
+    assert(!xml.sub!(%r!\s*license="SH6673"!s, 'ford').nil?)
+    assert(!xml.sub!(%r!\s*desc="Electric Windows"!s, '1').nil?)
+    assert(!xml.sub!(%r!\s*pn="6389733317-12"!s, '1').nil?)
+    assert(!xml.sub!(%r!\s*key="2"!s, '1').nil?)
+    assert(!xml.sub!(%r!\s*<option111!s, '<option').nil?)
+    assert(!xml.sub!(%r!\s*desc="Leather Seats"!s, '2').nil?)
+    assert(!xml.sub!(%r!\s*pn="3735498158-01"!s, '2').nil?)
+    assert(!xml.sub!(%r!\s*key="3"!s, '2').nil?)
+    assert(!xml.sub!(%r!\s*<option222!s, '<option').nil?)
+    assert(!xml.sub!(%r!\s*desc="Sun Roof"!s, '3').nil?)
+    assert(!xml.sub!(%r!\s*pn="5776155953-25"!s, '3').nil?)
+    assert(!xml.sub!(%r!\s*key="4"!s, '3').nil?)
+    assert(!xml.sub!(%r!\s*<option333!s, '<option').nil?)
+    assert(!xml.sub!(%r!\s*<carfordfordford>\s*(<option\s*/>\s*){3}</car>!s, 'CAR').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>\s*CAR\s*CAR\s*</\1>$!s, '').nil?)
+
+    # Check that empty hashes translate to empty tags
+    ref = {
+      'one' => {
+        'attr1' => 'avalue1',
+        'nest1' => [ 'nvalue1' ],
+        'nest2' => {}
+      },
+      'two' => {}
+    }
+
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert(!xml.sub!(%r!<nest2\s*></nest2\s*>\s*!, '<NNN>').nil?)
+    assert(!xml.sub!(%r!<nest1\s*>nvalue1</nest1\s*>\s*!, '<NNN>').nil?)
+    assert(!xml.sub!(%r!<one\s*attr1\s*=\s*"avalue1">\s*!, '<one>').nil?)
+    assert(!xml.sub!(%r!<one\s*>\s*<NNN>\s*<NNN>\s*</one>!, '<nnn>').nil?)
+    assert(!xml.sub!(%r!<two\s*></two\s*>\s*!, '<nnn>').nil?)
+    assert(!xml.sub!(%r!^\s*<(\w+)\s*>\s*<nnn>\s*<nnn>\s*</\1\s*>\s*$!, '').nil?)
+
+    # Check undefined values generate warnings 
+    ref = { 'tag' => nil }
+    assert_raises(ArgumentError) { XmlSimple.xml_out(ref) }
+
+    # Unless undef is mapped to empty elements
+    ref = { 'tag' => nil }
+    xml = XmlSimple.xml_out(ref, { 'suppress_empty' => nil, 'key_attr' => %w(name key id) })
+    assert(!xml.sub!(%r!^\s*<(\w*)\s*>\s*<tag\s*></tag\s*>\s*</\1\s*>\s*$!s, '').nil?)
+
+    # Test the keeproot option
+    ref = {
+      'seq' => {
+        'name' => 'alpha',
+        'alpha' => [ 1, 2, 3 ]
+      }
+    }
+    xml1 = XmlSimple.xml_out(ref, { 'root_name' => 'sequence', 'key_attr' => %w(name key id) })
+    xml2 = XmlSimple.xml_out({ 'sequence' => ref }, { 'keep_root' => true, 'key_attr' => %w(name key id) })
+    assert_equal(xml1, xml2)
+
+    # Test that items with text content are output correctly
+    # Expect: <opt one="1">text</opt>
+    ref = { 'one' => '1', 'content' => 'text' }
+    xml = XmlSimple.xml_out(ref, { 'key_attr' => %w(name key id) })
+    assert(!xml.sub!(%r!^\s*<opt\s+one="1">text</opt>\s*$!s, '').nil?)
+
+    # Even if we change the default value for the 'contentkey' option
+    ref = { 'one' => '1', 'text_content' => 'text' };
+    xml = XmlSimple.xml_out(ref, { 'content_key' => 'text_content', 'key_attr' => %w(name key id) })
+    assert(!xml.sub!(%r!^\s*<opt\s+one="1">text</opt>\s*$!s, '').nil?)
+
+    # and also if we add the '-' prefix
+    xml = XmlSimple.xml_out(ref, { 'content_key' => '-text_content', 'key_attr' => %w(name key id) })
+    assert(!xml.sub!(%r!^\s*<opt\s+one="1">text</opt>\s*$!s, '').nil?)
+
+    # Check 'noattr' option
+    ref = {
+      'attr1'  => 'value1',
+      'attr2'  => 'value2',
+      'nest'   => %w(one two three)
+    }
+
+    # Expect:
+    #
+    # <opt>
+    #   <attr1>value1</attr1>
+    #   <attr2>value2</attr2>
+    #   <nest>one</nest>
+    #   <nest>two</nest>
+    #   <nest>three</nest>
+    # </opt>
+    #
+    xml = XmlSimple.xml_out(ref, { 'no_attr' => true, 'key_attr' => %w(name key id) })
+    assert(xml !~ /=/s)
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert(!xml.sub!(%r!\s*<(attr1)>value1</\1>\s*!s, 'NEST').nil?)
+    assert(!xml.sub!(%r!\s*<(attr2)>value2</\1>\s*!s, 'NEST').nil?)
+    assert(!xml.sub!(%r!\s*<(nest)>one</\1>\s*<\1>two</\1>\s*<\1>three</\1>!s, 'NEST').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>(NEST\s*){3}</\1>$!s, '').nil?)
+
+    # Check noattr doesn't screw up keyattr
+    ref = {
+      'number' => {
+        'twenty one' => {
+          'dec' => '21',
+          'hex' => '0x15'
+        },
+        'thirty two' => {
+          'dec' => '32',
+          'hex' => '0x20'
+        }
+      }
+    }
+
+    # Expect:
+    #
+    # <opt>
+    #   <number>
+    #     <dec>21</dec>
+    #     <word>twenty one</word>
+    #     <hex>0x15</hex>
+    #   </number>
+    #   <number>
+    #     <dec>32</dec>
+    #     <word>thirty two</word>
+    #     <hex>0x20</hex>
+    #   </number>
+    # </opt>
+    #
+    xml = XmlSimple.xml_out(ref, { 'no_attr' => true, 'key_attr' => [ 'word' ] })
+    assert(xml !~ /=/s)
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(word) }))
+    assert(!xml.sub!(%r!\s*<(dec)>21</\1>\s*!s, '21').nil?)
+    assert(!xml.sub!(%r!\s*<(hex)>0x15</\1>\s*!s, '21').nil?)
+    assert(!xml.sub!(%r!\s*<(word)>twenty one</\1>\s*!s, '21').nil?)
+    assert(!xml.sub!(%r!\s*<(number)>212121</\1>\s*!s, 'NUM').nil?)
+    assert(!xml.sub!(%r!\s*<(dec)>32</\1>\s*!s, '32').nil?)
+    assert(!xml.sub!(%r!\s*<(hex)>0x20</\1>\s*!s, '32').nil?)
+    assert(!xml.sub!(%r!\s*<(word)>thirty two</\1>\s*!s, '32').nil?)
+    assert(!xml.sub!(%r!\s*<(number)>323232</\1>\s*!s, 'NUM').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>NUMNUM</\1>$!, '').nil?)
+
+    # Check grouped tags get ungrouped correctly
+    ref = {
+      'prefix' => 'before',
+      'dirs'   => [ '/usr/bin', '/usr/local/bin' ],
+      'suffix' => 'after'
+    }
+
+    # Expect:
+    #
+    # <opt>
+    #   <prefix>before</prefix>
+    #   <dirs>
+    #     <dir>/usr/bin</dir>
+    #     <dir>/usr/local/bin</dir>
+    #   </dirs>
+    #   <suffix>after</suffix>
+    # </opt>
+    #
+    xml = XmlSimple.xml_out(ref, {
+      'key_attr'    => %w(name key id),
+      'no_attr'     => true,
+      'group_tags'  => { 'dirs' => 'dir' }
+    })
+    assert(!xml.sub!(%r!\s*<(prefix)>before</\1>\s*!s, 'ELEM').nil?)
+    assert(!xml.sub!(%r!\s*<(suffix)>after</\1>\s*!s, 'ELEM').nil?)
+    assert(!xml.sub!(%r!\s*<dir>/usr/bin</dir>\s*<dir>/usr/local/bin</dir>\s*!s, 'LIST').nil?)
+    assert(!xml.sub!(%r!\s*<dirs>LIST</dirs>\s*!s, 'ELEM').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>ELEMELEMELEM</\1>$!, '').nil?)
+
+    # Try again with multiple groupings
+    ref = {
+      'dirs'  => [ '/usr/bin', '/usr/local/bin' ],
+      'terms' => [ 'vt100', 'xterm' ]
+    }
+
+    # Expect:
+    #
+    # <opt>
+    #   <dirs>
+    #     <dir>/usr/bin</dir>
+    #     <dir>/usr/local/bin</dir>
+    #   </dirs>
+    #   <terms>
+    #     <term>vt100</term>
+    #     <term>xterm</term>
+    #   </terms>
+    # </opt>
+    #
+    xml = XmlSimple.xml_out(ref, {
+      'key_attr'    => %w(name key id),
+      'no_attr'     => true,
+      'group_tags'  => { 'dirs' => 'dir', 'terms' => 'term' }
+    })
+
+    assert(!xml.sub!(%r!\s*<dir>/usr/bin</dir>\s*<dir>/usr/local/bin</dir>\s*!s, 'LIST').nil?)
+    assert(!xml.sub!(%r!\s*<dirs>LIST</dirs>\s*!s, 'ELEM').nil?)
+    assert(!xml.sub!(%r!\s*<term>vt100</term>\s*<term>xterm</term>\s*!s, 'LIST').nil?)
+    assert(!xml.sub!(%r!\s*<terms>LIST</terms>\s*!s, 'ELEM').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>ELEMELEM</\1>$!, '').nil?)
+
+    # Confirm unfolding and grouping work together
+    ref = {
+      'dirs'   => {
+        'first'   => { 'content' => '/usr/bin'       }, 
+        'second'  => { 'content' => '/usr/local/bin' }
+      }
+    }
+
+    # Expect:
+    #
+    # <opt>
+    #   <dirs>
+    #     <dir name="first">/usr/bin</dir>
+    #     <dir name="second">/usr/local/bin</dir>
+    #   </dirs>
+    # </opt>
+    #
+    xml = XmlSimple.xml_out(ref, {
+      'key_attr'    => { 'dir' => 'name'},
+      'group_tags'  => { 'dirs' => 'dir' }
+    })
+    assert(!xml.sub!(%r!\s*<dir\s+name="first">/usr/bin</dir>\s*!s, 'ITEM').nil?)
+    assert(!xml.sub!(%r!\s*<dir\s+name="second">/usr/local/bin</dir>\s*!s, 'ITEM').nil?)
+    assert(!xml.sub!(%r!\s*<dirs>ITEMITEM</dirs>\s*!s, 'GROUP').nil?)
+    assert(!xml.sub!(%r!^<(\w+)\s*>GROUP</\1>$!, '').nil?)
+
+    # Combine unfolding, grouping and stripped content - watch it fail :-(
+    ref = {
+      'dirs'   => {
+        'first'   => '/usr/bin',
+        'second'  => '/usr/local/bin'
+      }
+    }
+
+    # Expect:
+    #
+    # <opt>
+    #   <dirs first="/usr/bin" second="/usr/local/bin" />
+    # </opt>
+    #
+    xml = XmlSimple.xml_out(ref, {
+      'key_attr'    => { 'dir' => 'name'},
+      'group_tags'  => { 'dirs' => 'dir' },
+      'content_key' => '-content'
+    })
+    assert(!xml.sub!(%r!
+      ^<(\w+)>\s*
+        <dirs>\s*
+          <dir
+            (?:
+              \s+first="/usr/bin"
+             |\s+second="/usr/local/bin"
+            ){2}\s*
+          />\s*
+        </dirs>\s*
+      </\1>$!x, '').nil?)
+
+    # Check 'NoIndent' option
+    ref = { 'nest' => %w(one two three) }
+
+    # Expect:
+    #
+    # <opt><nest>one</nest><nest>two</nest><nest>three</nest></opt>
+    #
+    xml = XmlSimple.xml_out(ref, {
+      'key_attr'  => %w(name key id),
+      'no_indent' => true
+    })
+
+    assert_equal(ref, XmlSimple.xml_in(xml, { 'force_array' => false, 'key_attr' => %w(name key id) }))
+    assert_equal('<opt><nest>one</nest><nest>two</nest><nest>three</nest></opt>', xml)
+
+    # 'Stress test' with a data structure that maps to several thousand elements.
+    # Unfold elements with XmlSimple.xml_out() and fold them up again with XmlSimple.xml_in()
+    opt1 =  { 'TypeA' => {}, 'TypeB' => {}}
+    for i in 1 .. 40
+      for j in 1 .. i
+        opt1['TypeA'][i.to_s] = { 'Record' => {}}
+        opt1['TypeB'][i.to_s] = { 'Record' => {}}
+        opt1['TypeA'][i.to_s]['Record'][j.to_s] = { 'Hex' => sprintf("0x%04X", j) }
+        opt1['TypeB'][i.to_s]['Record'][j.to_s] = { 'Oct' => sprintf("%04o", j) }
+      end
+    end
+
+    xml = XmlSimple.xml_out(opt1, { 'key_attr' => { 'TypeA' => 'alpha', 'TypeB' => 'beta', 'Record' => 'id' }})
+    opt2 = XmlSimple.xml_in(xml, { 'key_attr' => { 'TypeA' => 'alpha', 'TypeB' => 'beta', 'Record' => 'id' } })
+    assert_equal(opt1, opt2)
+  end
+end
+
diff --git a/test/tc_perl_storable.rb b/test/tc_perl_storable.rb
new file mode 100755
index 0000000..ab955ff
--- /dev/null
+++ b/test/tc_perl_storable.rb
@@ -0,0 +1,133 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+require 'fileutils'
+
+# The test cases below are copied from the original Perl version,
+# because I wanted to behave the Ruby version exactly as the Perl
+# version. I left some comments, that maybe do not make a lot of
+# sense in the current Ruby version just to make it easier to find
+# changes between the current and future Perl versions of the
+# module.
+# Please note, that a major difference between the Perl and the Ruby
+# version is, that the defaults of the options 'force_array' and
+# 'key_attr' have changed.
+class TC_Perl_Cache < Test::Unit::TestCase # :nodoc:
+  # Wait until the current time is greater than the supplied value
+  def pass_time(target)
+    while Time::now.to_i <= target
+      sleep 1
+    end
+  end
+  
+  def test_perl_test_cases
+    src_file   = File.join(File.dirname(__FILE__), 'files', 'desertnet.src')
+    xml_file   = File.join(File.dirname(__FILE__), 'files', 'desertnet.xml')
+    cache_file = File.join(File.dirname(__FILE__), 'files', 'desertnet.stor')
+    raise "Test data is missing!" unless File::exist?(src_file)
+
+    # Make sure we can write to the filesystem and check it uses the same
+    # clock as the machine we're running on.
+    t0   = Time::now.to_i
+    file = File.open(xml_file, "w")
+    file.close
+    t1   = File::mtime(xml_file).to_i
+    t2   = Time::now.to_i
+    raise "Time moved backwards!" if (t1 < t0) || (t2 < t1)
+
+    # Initialise test data
+    expected  = {
+      'server' => {
+        'sahara' => {
+          'osversion' => '2.6',
+          'osname'    => 'solaris',
+          'address'   => [
+            '10.0.0.101',
+            '10.0.1.101'
+          ]
+        },
+        'gobi' => {
+          'osversion' => '6.5',
+          'osname'    => 'irix',
+          'address'   => '10.0.0.102'
+        },
+        'kalahari' => {
+          'osversion' => '2.0.34',
+          'osname'    => 'linux',
+          'address'   => [
+            '10.0.0.103',
+            '10.0.1.103'
+          ]
+        }
+      }
+    }
+
+    FileUtils.cp(src_file, xml_file)
+    FileUtils.rm(cache_file) if File::exist?(cache_file)
+    assert(!File::exist?(cache_file))
+
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal(expected, opt)
+    assert(!File::exist?(cache_file)) # No cache file was created.
+    pass_time(Time::now.to_i)
+
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'storable' })
+    assert_equal(expected, opt)
+    assert(File::exist?(cache_file)) # Cache file was created.
+    t0 = File::mtime(cache_file)     # Remember cache timestamp
+    pass_time(t0.to_i)
+
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'storable' })
+    assert_equal(expected, opt)
+    t1 = File::mtime(cache_file)
+    assert_equal(t0, t1)
+
+    pass_time(Time::now.to_i)
+    t0 = Time::now
+    File.open(xml_file, "a+") { |f| f.write("\n") } # Touch the XML file.
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'storable' })
+    assert_equal(expected, opt)
+    t2 = File::mtime(cache_file)
+    assert(t1.to_i != t2.to_i)
+
+    FileUtils.rm(xml_file)
+    assert(!File::exist?(xml_file))
+    file = File.open(xml_file, "w") # Re-create it (empty)
+    file.close
+    assert(File::exist?(xml_file))
+    assert(File::size(xml_file) == 0)
+    pass_time(File::mtime(xml_file).to_i) # But ensure cache file is newer
+    FileUtils.rm(cache_file)               # Seems to be rqd for test on Win32
+    File.open(cache_file, "w") { |f| f.write(Marshal.dump(expected, f)) }
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'storable' })
+    assert_equal(expected, opt)
+    t2 = File::mtime(cache_file)
+    pass_time(t2.to_i)
+    # Write some new data to the XML file
+    File.open(xml_file, "w") { |f| f.write('<opt one="1" two="2"></opt>' + "\n") }
+
+    # Parse with no caching
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id) })
+    assert_equal({ 'one' => '1', 'two' => '2' }, opt)
+    t0 = File::mtime(cache_file)
+    s0 = File::size(cache_file)
+    assert_equal(t0, t2)
+
+    # Parse again with caching enabled
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'storable' })
+    assert_equal({ 'one' => '1', 'two' => '2' }, opt)
+    t1 = File::mtime(cache_file)
+    s1 = File::size(cache_file)
+    assert((t0 != t1) || (s0 != s1)) # Content changes but date may not on Win32
+
+    FileUtils.cp(src_file, xml_file)
+    pass_time(t1.to_i)
+    opt = XmlSimple.xml_in(xml_file, { 'force_array' => false, 'key_attr' => %w(name key id), 'cache' => 'storable' })
+    assert_equal(expected, opt)
+
+    # Clean up.
+    FileUtils.rm(cache_file)
+    FileUtils.rm(xml_file)
+  end
+end
diff --git a/test/tc_string_in.rb b/test/tc_string_in.rb
new file mode 100755
index 0000000..a533bf7
--- /dev/null
+++ b/test/tc_string_in.rb
@@ -0,0 +1,324 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+class TC_String_In < Test::Unit::TestCase # :nodoc:
+  def test_simple_strings
+    simple = XmlSimple.new
+    expected = { 'username' => 'testuser', 'password' => 'frodo' }
+    xml_string = '<opt username="testuser" password="frodo"></opt>'
+    assert_equal(expected, simple.xml_in(xml_string))
+
+    xml_string = '<opt username="testuser" password="frodo" />'
+    assert_equal(expected, simple.xml_in(xml_string))
+
+    assert_equal(expected, XmlSimple.xml_in(xml_string))
+  end
+
+  def test_repeated_nested_elements
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <person firstname="Joe" lastname="Smith">
+        <email>joe@smith.com</email>
+        <email>jsmith@yahoo.com</email>
+      </person>
+      <person firstname="Bob" lastname="Smith">
+        <email>bob@smith.com</email>
+      </person>
+    </opt>
+    END_OF_XML
+    expected = {
+      'person' => [
+        {
+          'email'     => ['joe@smith.com', 'jsmith@yahoo.com'],
+          'firstname' => 'Joe',
+          'lastname'  => 'Smith'
+        },
+        {
+          'email'     => ['bob@smith.com'],
+          'firstname' => 'Bob',
+          'lastname'  => 'Smith'
+        }
+      ]
+    }
+    assert_equal(expected, simple.xml_in(xml_string))
+
+    expected = {
+      'person' => [
+        {
+          'email'     => ['joe@smith.com', 'jsmith@yahoo.com'],
+          'firstname' => 'Joe',
+          'lastname'  => 'Smith'
+        },
+        {
+          'email'     => 'bob@smith.com',
+          'firstname' => 'Bob',
+          'lastname'  => 'Smith'
+        }
+      ]
+    }
+    assert_equal(expected, simple.xml_in(xml_string, { 'force_array' => false }))
+  end
+
+  def test_keyattr_folding
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <person key="jsmith"  firstname="Joe" lastname="Smith" />
+      <person key="tsmith"  firstname="Tom" lastname="Smith" />
+      <person key="jbloggs" firstname="Joe" lastname="Bloggs" />
+    </opt>
+    END_OF_XML
+    expected = {
+      'person' => {
+        'jbloggs' => {
+          'firstname' => 'Joe',
+          'lastname'  => 'Bloggs'
+        },
+        'tsmith' => {
+          'firstname' => 'Tom',
+          'lastname'  => 'Smith'
+        },
+        'jsmith' => {
+          'firstname' => 'Joe',
+          'lastname'  => 'Smith'
+        }
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, { 'key_attr' => %w(key) }))
+  end
+
+  def test_text_and_attributes
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <one>first</one>
+      <two attr="value">second</two>
+    </opt>
+    END_OF_XML
+    expected = {
+      'one' => [ 'first' ],
+      'two' => [ { 'attr' => 'value', 'content' => 'second' } ]
+    }
+    assert_equal(expected, simple.xml_in(xml_string))
+
+    expected = {
+      'one' => 'first',
+      'two' => { 'attr' => 'value', 'content' => 'second' }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, { 'force_array' => false }))
+  end
+
+  def test_anonymous_arrays
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <head><anon>Col 1</anon><anon>Col 2</anon><anon>Col 3</anon></head>
+      <data><anon>R1C1</anon><anon>R1C2</anon><anon>R1C3</anon></data>
+      <data><anon>R2C1</anon><anon>R2C2</anon><anon>R2C3</anon></data>
+      <data><anon>R3C1</anon><anon>R3C2</anon><anon>R3C3</anon></data>
+    </opt>
+    END_OF_XML
+    expected = {
+      'head' => [
+        [ 'Col 1', 'Col 2', 'Col 3' ]
+      ],
+      'data' => [
+        [ 'R1C1', 'R1C2', 'R1C3' ],
+        [ 'R2C1', 'R2C2', 'R2C3' ],
+        [ 'R3C1', 'R3C2', 'R3C3' ]
+      ]
+    }
+    assert_equal(expected, simple.xml_in(xml_string))
+
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <head><silly>Col 1</silly><silly>Col 2</silly><silly>Col 3</silly></head>
+      <data><silly>R1C1</silly><silly>R1C2</silly><silly>R1C3</silly></data>
+      <data><silly>R2C1</silly><silly>R2C2</silly><silly>R2C3</silly></data>
+      <data><silly>R3C1</silly><silly>R3C2</silly><silly>R3C3</silly></data>
+    </opt>
+    END_OF_XML
+    expected = {
+      'head' => [
+        [ 'Col 1', 'Col 2', 'Col 3' ]
+      ],
+      'data' => [
+        [ 'R1C1', 'R1C2', 'R1C3' ],
+        [ 'R2C1', 'R2C2', 'R2C3' ],
+        [ 'R3C1', 'R3C2', 'R3C3' ]
+      ]
+    }
+    assert_equal(expected, simple.xml_in(xml_string, { 'anonymous_tag' => 'silly' }))
+
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <anon><anon>Col 1</anon><anon>Col 2</anon></anon>
+      <anon><anon>R1C1</anon><anon>R1C2</anon></anon>
+      <anon><anon>R2C1</anon><anon>R2C2</anon></anon>
+    </opt>
+    END_OF_XML
+    expected = [
+        [ 'Col 1', 'Col 2' ],
+        [ 'R1C1', 'R1C2' ],
+        [ 'R2C1', 'R2C2' ]
+    ]
+    assert_equal(expected, simple.xml_in(xml_string))
+
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <silly><silly>Col 1</silly><silly>Col 2</silly></silly>
+      <silly><silly>R1C1</silly><silly>R1C2</silly></silly>
+      <silly><silly>R2C1</silly><silly>R2C2</silly></silly>
+    </opt>
+    END_OF_XML
+    expected = [
+        [ 'Col 1', 'Col 2' ],
+        [ 'R1C1', 'R1C2' ],
+        [ 'R2C1', 'R2C2' ]
+    ]
+    assert_equal(expected, simple.xml_in(xml_string, { 'anonymous_tag' => 'silly' }))
+  end
+
+  def test_collapse_again
+    simple = XmlSimple.new
+    xml_string = '<opt><item name="one">First</item><item name="two">Second</item></opt>'
+    expected = {
+      'item' => {
+        'one' => 'First',
+        'two' => 'Second'
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'KeyAttr'    => { 'item' => 'name' },
+      'ForceArray' => [ 'item' ],
+      'ContentKey' => '-content'
+    }))
+
+    expected = {
+      'item' => {
+        'one' => { 'content' => 'First'  },
+        'two' => { 'content' => 'Second' }
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'KeyAttr'    => { 'item' => 'name' },
+      'ForceArray' => [ 'item' ],
+      'ContentKey' => 'content'
+    }))
+  end
+
+  def test_force_array_regex
+    simple = XmlSimple.new
+    xml_string = '<opt><item name="one">First</item><item name="two">Second</item></opt>'
+    expected = {
+      'item' => {
+        'one' => { 'content' => 'First'  },
+        'two' => { 'content' => 'Second' }
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'KeyAttr'    => { 'item' => 'name' },
+      'ForceArray' => [ /item/ ]
+    }))
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'KeyAttr'    => { 'item' => 'name' },
+      'ForceArray' => [ /it/ ]
+    }))
+  end
+
+  def test_group_tags
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <searchpath>
+        <dir>/usr/bin</dir>
+        <dir>/usr/local/bin</dir>
+        <dir>/usr/X11/bin</dir>
+      </searchpath>
+    </opt>
+    END_OF_XML
+    
+    expected = {
+      'searchpath' => {
+        'dir' => [ '/usr/bin', '/usr/local/bin', '/usr/X11/bin' ]
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'ForceArray' => false,
+      'KeyAttr'    => %w(name key id)
+    }))
+
+    expected = {
+      'searchpath' => [ '/usr/bin', '/usr/local/bin', '/usr/X11/bin' ]
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'ForceArray' => false,
+      'KeyAttr'    => %w(name key id),
+      'GroupTags'  => { 'searchpath' => 'dir' }
+    }))
+  end
+
+  def test_normalise_space
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <searchpath>
+        <dir>  /usr/bin</dir>
+        <dir>/usr/local/bin  </dir>
+        <dir>  /usr   /X11/bin  </dir>
+      </searchpath>
+    </opt>
+    END_OF_XML
+    
+    expected = {
+      'searchpath' => {
+        'dir' => [ '  /usr/bin', '/usr/local/bin  ', '  /usr   /X11/bin  ' ]
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'ForceArray'     => false,
+      'KeyAttr'        => %w(name key id),
+      'NormaliseSpace' => 0
+    }))
+
+    expected = {
+      'searchpath' => {
+        'dir' => [ '/usr/bin', '/usr/local/bin', '/usr /X11/bin' ]
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'ForceArray'     => false,
+      'KeyAttr'        => %w(name key id),
+      'NormaliseSpace' => 2
+    }))
+  end
+
+  def test_var_attr
+    simple = XmlSimple.new
+    xml_string = <<-'END_OF_XML'
+    <opt>
+      <dir name="prefix">/usr/local/apache</dir>
+      <dir name="exec_prefix">${prefix}</dir>
+      <dir name="bindir">${exec_prefix}/bin</dir>
+    </opt>
+    END_OF_XML
+    
+    expected = {
+      'dir' => {
+        'prefix'      => '/usr/local/apache',
+        'exec_prefix' => '/usr/local/apache',
+        'bindir'      => '/usr/local/apache/bin'
+      }
+    }
+    assert_equal(expected, simple.xml_in(xml_string, {
+      'ForceArray' => false,
+      'KeyAttr'    => %w(name key id),
+      'VarAttr'    => 'name',
+      'ContentKey' => '-content'
+    }))
+  end
+end
+
diff --git a/test/tc_symbol.rb b/test/tc_symbol.rb
new file mode 100755
index 0000000..3281864
--- /dev/null
+++ b/test/tc_symbol.rb
@@ -0,0 +1,23 @@
+$: << File.join(File.dirname(__FILE__), '../lib')
+
+require 'test/unit'
+require 'xmlsimple'
+
+# This test case will test the KeyToSymbol option
+# added by Keith Veleba keith (at) veleba.net on 6/21/2006 
+class TC_Symbol < Test::Unit::TestCase # :nodoc:
+  def test_key_to_symbol
+    symbol_file = File.join(File.dirname(__FILE__), 'files', 'symbol.xml')
+    expected = {
+                :x => ["Hello"],
+                :y => ["World"],
+                :z => [{
+                       :inner => ["Inner"]
+                      }]
+               }
+    xml = XmlSimple.xml_in(symbol_file, { 'KeyToSymbol' => true })
+    assert_equal(expected, xml)
+    xml = XmlSimple.xml_in(symbol_file, { 'key_to_symbol' => true })
+    assert_equal(expected, xml)
+  end
+end
diff --git a/xml-simple.gemspec b/xml-simple.gemspec
old mode 100644
new mode 100755
index edaa775..9b8c239
--- a/xml-simple.gemspec
+++ b/xml-simple.gemspec
@@ -1,33 +1,12 @@
-#########################################################
-# This file has been automatically generated by gem2tgz #
-#########################################################
-# -*- encoding: utf-8 -*-
-# stub: xml-simple 1.1.9 ruby lib
-
 Gem::Specification.new do |s|
-  s.name = "xml-simple".freeze
+  s.name = %q{xml-simple}
   s.version = "1.1.9"
-
-  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
-  s.require_paths = ["lib".freeze]
-  s.authors = ["Maik Schmidt".freeze]
-  s.date = "2021-01-18"
-  s.email = "contact@maik-schmidt.de".freeze
-  s.files = ["lib/xmlsimple.rb".freeze]
-  s.homepage = "https://github.com/maik/xml-simple".freeze
-  s.licenses = ["MIT".freeze]
-  s.rubygems_version = "2.7.6.2".freeze
-  s.summary = "A simple API for XML processing.".freeze
-
-  if s.respond_to? :specification_version then
-    s.specification_version = 4
-
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
-      s.add_runtime_dependency(%q<rexml>.freeze, [">= 0"])
-    else
-      s.add_dependency(%q<rexml>.freeze, [">= 0"])
-    end
-  else
-    s.add_dependency(%q<rexml>.freeze, [">= 0"])
-  end
+  s.date = %q{2021-01-18}
+  s.summary = %q{A simple API for XML processing.}
+  s.email = %q{contact@maik-schmidt.de}
+  s.homepage = %q{https://github.com/maik/xml-simple}
+  s.license = "MIT"
+  s.authors = ["Maik Schmidt"]
+  s.files = ["lib/xmlsimple.rb"]
+  s.add_runtime_dependency "rexml" 
 end

More details

Full run details