Class: XmlSimple

### Home Classes Methods

### In Files

- lib/xmlsimple.rb

### Parent

Object

### Namespace

- CLASS XmlSimple::Cache

### Methods

- ::new
- ::xml_in
- ::xml_out
- #collapse
- #collapse_content
- #collapse_text_node
- #empty
- #escape_value
- #find_xml_file
- #fold_array
- #fold_array_by_name
- #fold_arrays
- #force_array?
- #get_attributes
- #get_var
- #handle_options
- #has_mixed_content?
- #hash_to_array
- #load_xml_file
- #merge
- #node_to_text
- #normalise_space
- #normalize_option_names
- #parse
- #put_into_cache
- #scalar
- #set_var
- #value_to_xml
- #xml_in
- #xml_out

### Included Modules

- REXML

### Class Index

Quicksearch

- XmlSimple
- XmlSimple::Cache

No matching classes.

# XmlSimple

Easy API to maintain XML (especially configuration files).

### Constants

KNOWN_OPTIONS

  Declare options that are valid for xml_in and xml_out.

DEF_KEY_ATTRIBUTES

  Define some reasonable defaults.

DEF_ROOT_NAME
DEF_CONTENT_KEY
DEF_XML_DECLARATION
DEF_ANONYMOUS_TAG
DEF_FORCE_ARRAY
DEF_INDENTATION
DEF_KEY_TO_SYMBOL

### Public Class Methods

new(defaults = nil) click to toggle source

Creates and intializes a new XmlSimple object.

defaults | Default values for options.

         # File lib/xmlsimple.rb, line 128
    128:   def initialize(defaults = nil)
    129:     unless defaults.nil? || defaults.instance_of?(Hash)
    130:       raise ArgumentError, "Options have to be a Hash."
    131:     end
    132:     @default_options = normalize_option_names(defaults, (KNOWN_OPTIONS['in'] + KNOWN_OPTIONS['out']).uniq)
    133:     @options = Hash.new
    134:     @_var_values = nil
    135:   end

xml_in(string = nil, options = nil) click to toggle source

This is the functional version of the instance method xml_in.

         # File lib/xmlsimple.rb, line 201
    201:   def XmlSimple.xml_in(string = nil, options = nil)
    202:     xml_simple = XmlSimple.new
    203:     xml_simple.xml_in(string, options)
    204:   end

xml_out(hash, options = nil) click to toggle source

This is the functional version of the instance method xml_out.

         # File lib/xmlsimple.rb, line 257
    257:   def XmlSimple.xml_out(hash, options = nil)
    258:     xml_simple = XmlSimple.new
    259:     xml_simple.xml_out(hash, options)
    260:   end

### Public Instance Methods

xml_in(string = nil, options = nil) click to toggle source

Converts an XML document in the same way as the Perl module XML::Simple.

string | XML source. Could be one of the following: nil: Tries to load and parse ’.xml’. filename: Tries to load and parse filename. IO object: Reads from object until EOF is detected and parses result. XML string: Parses string.
options | Options to be used.

         # File lib/xmlsimple.rb, line 149
    149:   def xml_in(string = nil, options = nil)
    150:     handle_options('in', options)
    151:
    152:     # If no XML string or filename was supplied look for scriptname.xml.
    153:     if string.nil?
    154:       string = File::basename($0).dup
    155:       string.sub!(/\.[^.]+$/, '')
    156:       string += '.xml'
    157:
    158:       directory = File::dirname($0)
    159:       @options['searchpath'].unshift(directory) unless directory.nil?
    160:     end
    161:
    162:     if string.instance_of?(String)
    163:       if string =~ /<.*?>/
    164:         @doc = parse(string)
    165:       elsif string == '-'
    166:         @doc = parse($stdin.read)
    167:       else
    168:         filename = find_xml_file(string, @options['searchpath'])
    169:
    170:         if @options.has_key?('cache')
    171:           @options['cache'].each { |scheme|
    172:             case(scheme)
    173:             when 'storable'
    174:               content = @@cache.restore_storable(filename)
    175:             when 'mem_share'
    176:               content = @@cache.restore_mem_share(filename)
    177:             when 'mem_copy'
    178:               content = @@cache.restore_mem_copy(filename)
    179:             else
    180:               raise ArgumentError, "Unsupported caching scheme: <#{scheme}>."
    181:             end
    182:             return content if content
    183:           }
    184:         end
    185:
    186:         @doc = load_xml_file(filename)
    187:       end
    188:     elsif string.kind_of?(IO) || string.kind_of?(StringIO) || string.kind_of?(Zlib::GzipReader)
    189:       @doc = parse(string.read)
    190:     else
    191:       raise ArgumentError, "Could not parse object of type: <#{string.type}>."
    192:     end
    193:
    194:     result = collapse(@doc.root)
    195:     result = @options['keeproot'] ? merge({}, @doc.root.name, result) : result
    196:     put_into_cache(result, filename)
    197:     result
    198:   end

xml_out(ref, options = nil) click to toggle source

Converts a data structure into an XML document.

ref | Reference to data structure to be converted into XML.
options | Options to be used.

         # File lib/xmlsimple.rb, line 212
    212:   def xml_out(ref, options = nil)
    213:     handle_options('out', options)
    214:     if ref.instance_of?(Array)
    215:       ref = { @options['anonymoustag'] => ref }
    216:     end
    217:
    218:     if @options['keeproot']
    219:       keys = ref.keys
    220:       if keys.size == 1
    221:         ref = ref[keys[0]]
    222:         @options['rootname'] = keys[0]
    223:       end
    224:     elsif @options['rootname'] == ''
    225:       if ref.instance_of?(Hash)
    226:         refsave = ref
    227:         ref = {}
    228:         refsave.each { |key, value|
    229:           if !scalar(value)
    230:             ref[key] = value
    231:           else
    232:             ref[key] = [ value.to_s ]
    233:           end
    234:         }
    235:       end
    236:     end
    237:
    238:     @ancestors = []
    239:     xml = value_to_xml(ref, @options['rootname'], '')
    240:     @ancestors = nil
    241:
    242:     if @options['xmldeclaration']
    243:       xml = @options['xmldeclaration'] + "\n" + xml
    244:     end
    245:
    246:     if @options.has_key?('outputfile')
    247:       if @options['outputfile'].kind_of?(IO)
    248:         return @options['outputfile'].write(xml)
    249:       else
    250:         File.open(@options['outputfile'], "w") { |file| file.write(xml) }
    251:       end
    252:     end
    253:     xml
    254:   end

### Private Instance Methods

collapse(element) click to toggle source

Actually converts an XML document element into a data structure.

element | The document element to be collapsed.

         # File lib/xmlsimple.rb, line 461
    461:   def collapse(element)
    462:     result = @options['noattr'] ? {} : get_attributes(element)
    463:
    464:     if @options['normalisespace'] == 2
    465:       result.each { |k, v| result[k] = normalise_space(v) }
    466:     end
    467:
    468:     if element.has_elements?
    469:       element.each_element { |child|
    470:         value = collapse(child)
    471:         if empty(value) && (element.attributes.empty? || @options['noattr'])
    472:           next if @options.has_key?('suppressempty') && @options['suppressempty'] == true
    473:         end
    474:         result = merge(result, child.name, value)
    475:       }
    476:       if has_mixed_content?(element)
    477:         # normalisespace?
    478:         content = element.texts.map { |x| x.to_s }
    479:         content = content[0] if content.size == 1
    480:         result[@options['contentkey']] = content
    481:       end
    482:     elsif element.has_text? # i.e. it has only text.
    483:       return collapse_text_node(result, element)
    484:     end
    485:
    486:     # Turn Arrays into Hashes if key fields present.
    487:     count = fold_arrays(result)
    488:
    489:     # Disintermediate grouped tags.
    490:     if @options.has_key?('grouptags')
    491:       result.each { |key, value|
    492:         next unless (value.instance_of?(Hash) && (value.size == 1))
    493:         child_key, child_value = value.to_a[0]
    494:         if @options['grouptags'][key] == child_key
    495:           result[key] = child_value
    496:         end
    497:       }
    498:     end
    499:
    500:     # Fold Hashes containing a single anonymous Array up into just the Array.
    501:     if count == 1
    502:       anonymoustag = @options['anonymoustag']
    503:       if result.has_key?(anonymoustag) && result[anonymoustag].instance_of?(Array)
    504:         return result[anonymoustag]
    505:       end
    506:     end
    507:
    508:     if result.empty? && @options.has_key?('suppressempty')
    509:       return @options['suppressempty'] == '' ? '' : nil
    510:     end
    511:
    512:     result
    513:   end

collapse_content(hash) click to toggle source

Tries to collapse a Hash even more ;-)

hash | Hash to be collapsed again.

         # File lib/xmlsimple.rb, line 624
    624:   def collapse_content(hash)
    625:     content_key = @options['contentkey']
    626:     hash.each_value { |value|
    627:       return hash unless value.instance_of?(Hash) && value.size == 1 && value.has_key?(content_key)
    628:       hash.each_key { |key| hash[key] = hash[key][content_key] }
    629:     }
    630:     hash
    631:   end

collapse_text_node(hash, element) click to toggle source

Collapses a text node and merges it with an existing Hash, if possible. Thanks to Curtis Schofield for reporting a subtle bug.

hash | Hash to merge text node value with, if possible.
element | Text node to be collapsed.

         # File lib/xmlsimple.rb, line 523
    523:   def collapse_text_node(hash, element)
    524:     value = node_to_text(element)
    525:     if empty(value) && !element.has_attributes?
    526:       return {}
    527:     end
    528:
    529:     if element.has_attributes? && !@options['noattr']
    530:       return merge(hash, @options['contentkey'], value)
    531:     else
    532:       if @options['forcecontent']
    533:         return merge(hash, @options['contentkey'], value)
    534:       else
    535:         return value
    536:       end
    537:     end
    538:   end

empty(value) click to toggle source

Checks, if an object is nil, an empty String or an empty Hash. Thanks to Norbert Gawor for a bugfix.

value | Value to be checked for emptyness.

         # File lib/xmlsimple.rb, line 918
    918:   def empty(value)
    919:     case value
    920:       when Hash
    921:         return value.empty?
    922:       when String
    923:         return value !~ /\S/
    924:       else
    925:         return value.nil?
    926:     end
    927:   end

escape_value(data) click to toggle source

Replaces XML markup characters by their external entities.

data | The string to be escaped.

         # File lib/xmlsimple.rb, line 900
    900:   def escape_value(data)
    901:     Text::normalize(data)
    902:   end

find_xml_file(file, searchpath) click to toggle source

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.

filename | Name of the file to search for.
searchpath | List of paths to search in.

         # File lib/xmlsimple.rb, line 970
    970:   def find_xml_file(file, searchpath)
    971:     filename = File::basename(file)
    972:
    973:     if filename != file
    974:       return file if File::file?(file)
    975:     else
    976:       searchpath.each { |path|
    977:         full_path = File::join(path, filename)
    978:         return full_path if File::file?(full_path)
    979:       }
    980:     end
    981:
    982:     if searchpath.empty?
    983:       return file if File::file?(file)
    984:       raise ArgumentError, "File does not exist: #{file}."
    985:     end
    986:     raise ArgumentError, "Could not find <#{filename}> in <#{searchpath.join(':')}>"
    987:   end

fold_array(array) click to toggle source

Folds an Array to a Hash, if possible. Folding happens according to the content of keyattr, which has to be an array.

array | Array to be folded.

         # File lib/xmlsimple.rb, line 568
    568:   def fold_array(array)
    569:     hash = Hash.new
    570:     array.each { |x|
    571:       return array unless x.instance_of?(Hash)
    572:       key_matched = false
    573:       @options['keyattr'].each { |key|
    574:         if x.has_key?(key)
    575:           key_matched = true
    576:           value = x[key]
    577:           return array if value.instance_of?(Hash) || value.instance_of?(Array)
    578:           value = normalise_space(value) if @options['normalisespace'] == 1
    579:           x.delete(key)
    580:           hash[value] = x
    581:           break
    582:         end
    583:       }
    584:       return array unless key_matched
    585:     }
    586:     hash = collapse_content(hash) if @options['collapseagain']
    587:     hash
    588:   end

fold_array_by_name(name, array) click to toggle source

Folds an Array to a Hash, if possible. Folding happens according to the content of keyattr, which has to be a Hash.

name | Name of the attribute to be folded upon.
array | Array to be folded.

         # File lib/xmlsimple.rb, line 598
    598:   def fold_array_by_name(name, array)
    599:     return array unless @options['keyattr'].has_key?(name)
    600:     key, flag = @options['keyattr'][name]
    601:
    602:     hash = Hash.new
    603:     array.each { |x|
    604:       if x.instance_of?(Hash) && x.has_key?(key)
    605:         value = x[key]
    606:         return array if value.instance_of?(Hash) || value.instance_of?(Array)
    607:         value = normalise_space(value) if @options['normalisespace'] == 1
    608:         hash[value] = x
    609:         hash[value]["-#{key}"] = hash[value][key] if flag == '-'
    610:         hash[value].delete(key) unless flag == '+'
    611:       else
    612:         $stderr.puts("Warning: <#{name}> element has no '#{key}' attribute.")
    613:         return array
    614:       end
    615:     }
    616:     hash = collapse_content(hash) if @options['collapseagain']
    617:     hash
    618:   end

fold_arrays(hash) click to toggle source

Folds all arrays in a Hash.

hash | Hash to be folded.

         # File lib/xmlsimple.rb, line 544
    544:   def fold_arrays(hash)
    545:     fold_amount = 0
    546:     keyattr = @options['keyattr']
    547:     if (keyattr.instance_of?(Array) || keyattr.instance_of?(Hash))
    548:       hash.each { |key, value|
    549:         if value.instance_of?(Array)
    550:           if keyattr.instance_of?(Array)
    551:             hash[key] = fold_array(value)
    552:           else
    553:             hash[key] = fold_array_by_name(key, value)
    554:           end
    555:           fold_amount += 1
    556:         end
    557:       }
    558:     end
    559:     fold_amount
    560:   end

force_array?(key) click to toggle source

Checks, if the ‘forcearray’ option has to be used for a certain key.

         # File lib/xmlsimple.rb, line 689
    689:   def force_array?(key)
    690:     return false if key == @options['contentkey']
    691:     return true if @options['forcearray'] == true
    692:     forcearray = @options['forcearray']
    693:     if forcearray.instance_of?(Hash)
    694:       return true if forcearray.has_key?(key)
    695:       return false unless forcearray.has_key?('_regex')
    696:       forcearray['_regex'].each { |x| return true if key =~ x }
    697:     end
    698:     return false
    699:   end

get_attributes(node) click to toggle source

Converts the attributes array of a document node into a Hash. Returns an empty Hash, if node has no attributes.

node | Document node to extract attributes from.

         # File lib/xmlsimple.rb, line 706
    706:   def get_attributes(node)
    707:     attributes = {}
    708:     if @options['attrprefix']
    709:       node.attributes.each { |n,v| attributes["@" + n] = v }
    710:     else
    711:       node.attributes.each { |n,v| attributes[n] = v }
    712:     end
    713:     attributes
    714:   end

get_var(name) click to toggle source

Called during variable substitution to get the value for the named variable.

         # File lib/xmlsimple.rb, line 737
    737:   def get_var(name)
    738:     if @_var_values.has_key?(name)
    739:       return @_var_values[name]
    740:     else
    741:       return "${#{name}}"
    742:     end
    743:   end

handle_options(direction, options) click to toggle source

Merges a set of options with the default options.

direction | ‘in’: If options should be handled for xml_in. ‘out’: If options should be handled for xml_out.
options | Options to be merged with the default options.

         # File lib/xmlsimple.rb, line 319
    319:   def handle_options(direction, options)
    320:     @options = options || Hash.new
    321:
    322:     raise ArgumentError, "Options must be a Hash!" unless @options.instance_of?(Hash)
    323:
    324:     unless KNOWN_OPTIONS.has_key?(direction)
    325:       raise ArgumentError, "Unknown direction: <#{direction}>."
    326:     end
    327:
    328:     known_options = KNOWN_OPTIONS[direction]
    329:     @options = normalize_option_names(@options, known_options)
    330:
    331:     unless @default_options.nil?
    332:       known_options.each { |option|
    333:         unless @options.has_key?(option)
    334:           if @default_options.has_key?(option)
    335:             @options[option] = @default_options[option]
    336:           end
    337:         end
    338:       }
    339:     end
    340:
    341:     unless @options.has_key?('noattr')
    342:         @options['noattr'] = false
    343:     end
    344:
    345:     if @options.has_key?('rootname')
    346:       @options['rootname'] = '' if @options['rootname'].nil?
    347:     else
    348:       @options['rootname'] = DEF_ROOT_NAME
    349:     end
    350:
    351:     if @options.has_key?('xmldeclaration') && @options['xmldeclaration'] == true
    352:       @options['xmldeclaration'] = DEF_XML_DECLARATION
    353:     end
    354:
    355:     @options['keytosymbol'] = DEF_KEY_TO_SYMBOL unless @options.has_key?('keytosymbol')
    356:
    357:     if @options.has_key?('contentkey')
    358:       if @options['contentkey'] =~ /^-(.*)$/
    359:         @options['contentkey']    = $1
    360:         @options['collapseagain'] = true
    361:       end
    362:     else
    363:       @options['contentkey'] = DEF_CONTENT_KEY
    364:     end
    365:
    366:     unless @options.has_key?('normalisespace')
    367:       @options['normalisespace'] = @options['normalizespace']
    368:     end
    369:     @options['normalisespace'] = 0 if @options['normalisespace'].nil?
    370:
    371:     if @options.has_key?('searchpath')
    372:       unless @options['searchpath'].instance_of?(Array)
    373:         @options['searchpath'] = [ @options['searchpath'] ]
    374:       end
    375:     else
    376:       @options['searchpath'] = []
    377:     end
    378:
    379:     if @options.has_key?('cache') && scalar(@options['cache'])
    380:       @options['cache'] = [ @options['cache'] ]
    381:     end
    382:
    383:     @options['anonymoustag'] = DEF_ANONYMOUS_TAG unless @options.has_key?('anonymoustag')
    384:
    385:     if !@options.has_key?('indent') || @options['indent'].nil?
    386:       @options['indent'] = DEF_INDENTATION
    387:     end
    388:
    389:     @options['indent'] = '' if @options.has_key?('noindent')
    390:
    391:     # Special cleanup for 'keyattr' which could be an array or
    392:     # a hash or left to default to array.
    393:     if @options.has_key?('keyattr')
    394:       if !scalar(@options['keyattr'])
    395:         # Convert keyattr => { elem => '+attr' }
    396:         #      to keyattr => { elem => ['attr', '+'] }
    397:         if @options['keyattr'].instance_of?(Hash)
    398:           @options['keyattr'].each { |key, value|
    399:             if value =~ /^([-+])?(.*)$/
    400:               @options['keyattr'][key] = [$2, $1 ? $1 : '']
    401:             end
    402:           }
    403:         elsif !@options['keyattr'].instance_of?(Array)
    404:           raise ArgumentError, "'keyattr' must be String, Hash, or Array!"
    405:         end
    406:       else
    407:         @options['keyattr'] = [ @options['keyattr'] ]
    408:       end
    409:     else
    410:       @options['keyattr'] = DEF_KEY_ATTRIBUTES
    411:     end
    412:
    413:     if @options.has_key?('forcearray')
    414:       if @options['forcearray'].instance_of?(Regexp)
    415:         @options['forcearray'] = [ @options['forcearray'] ]
    416:       end
    417:
    418:       if @options['forcearray'].instance_of?(Array)
    419:         force_list = @options['forcearray']
    420:         unless force_list.empty?
    421:           @options['forcearray'] = {}
    422:           force_list.each { |tag|
    423:             if tag.instance_of?(Regexp)
    424:               unless @options['forcearray']['_regex'].instance_of?(Array)
    425:                 @options['forcearray']['_regex'] = []
    426:               end
    427:               @options['forcearray']['_regex'] << tag
    428:             else
    429:               @options['forcearray'][tag] = true
    430:             end
    431:           }
    432:         else
    433:           @options['forcearray'] = false
    434:         end
    435:       else
    436:         @options['forcearray'] = @options['forcearray'] ? true : false
    437:       end
    438:     else
    439:       @options['forcearray'] = DEF_FORCE_ARRAY
    440:     end
    441:
    442:     if @options.has_key?('grouptags') && !@options['grouptags'].instance_of?(Hash)
    443:       raise ArgumentError, "Illegal value for 'GroupTags' option - expected a Hash."
    444:     end
    445:
    446:     if @options.has_key?('variables') && !@options['variables'].instance_of?(Hash)
    447:       raise ArgumentError, "Illegal value for 'Variables' option - expected a Hash."
    448:     end
    449:
    450:     if @options.has_key?('variables')
    451:       @_var_values = @options['variables']
    452:     elsif @options.has_key?('varattr')
    453:       @_var_values = {}
    454:     end
    455:   end

has_mixed_content?(element) click to toggle source

Determines, if a document element has mixed content.

element | Document element to be checked.

         # File lib/xmlsimple.rb, line 720
    720:   def has_mixed_content?(element)
    721:     if element.has_text? && element.has_elements?
    722:       return true if element.texts.join('') !~ /^\s*$/
    723:     end
    724:     false
    725:   end

hash_to_array(parent, hashref) click to toggle source

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.

parent |
hashref | Reference to the hash to be unfolded.

         # File lib/xmlsimple.rb, line 881
    881:   def hash_to_array(parent, hashref)
    882:     arrayref = []
    883:     hashref.each { |key, value|
    884:       return hashref unless value.instance_of?(Hash)
    885:
    886:       if @options['keyattr'].instance_of?(Hash)
    887:         return hashref unless @options['keyattr'].has_key?(parent)
    888:         arrayref << { @options['keyattr'][parent][0] => key }.update(value)
    889:       else
    890:         arrayref << { @options['keyattr'][0] => key }.update(value)
    891:       end
    892:     }
    893:     arrayref
    894:   end

load_xml_file(filename) click to toggle source

Loads and parses an XML configuration file.

filename | Name of the configuration file to be loaded.

The following exceptions may be raised:

Errno::ENOENT | If the specified file does not exist.
REXML::ParseException | If the specified file is not wellformed.

          # File lib/xmlsimple.rb, line 1000
    1000:   def load_xml_file(filename)
    1001:     parse(IO::read(filename))
    1002:   end

merge(hash, key, value) click to toggle source

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.

hash | Hash to add key/value pair to.
key | Key to be added.
value | Value to be associated with key.

         # File lib/xmlsimple.rb, line 644
    644:   def merge(hash, key, value)
    645:     if value.instance_of?(String)
    646:       value = normalise_space(value) if @options['normalisespace'] == 2
    647:
    648:       # do variable substitutions
    649:       unless @_var_values.nil? || @_var_values.empty?
    650:         value.gsub!(/\$\{(\w+)\}/) { |x| get_var($1) }
    651:       end
    652:
    653:       # look for variable definitions
    654:       if @options.has_key?('varattr')
    655:         varattr = @options['varattr']
    656:         if hash.has_key?(varattr)
    657:           set_var(hash[varattr], value)
    658:         end
    659:       end
    660:     end
    661:
    662:     #patch for converting keys to symbols
    663:     if @options.has_key?('keytosymbol')
    664:       if @options['keytosymbol'] == true
    665:         key = key.to_s.downcase.to_sym
    666:       end
    667:     end
    668:
    669:     if hash.has_key?(key)
    670:       if hash[key].instance_of?(Array)
    671:         hash[key] << value
    672:       else
    673:         hash[key] = [ hash[key], value ]
    674:       end
    675:     elsif value.instance_of?(Array) # Handle anonymous arrays.
    676:       hash[key] = [ value ]
    677:     else
    678:       if force_array?(key)
    679:         hash[key] = [ value ]
    680:       else
    681:         hash[key] = value
    682:       end
    683:     end
    684:     hash
    685:   end

node_to_text(node, default = nil) click to toggle source

Converts a document node into a String. If the node could not be converted into a String for any reason, default will be returned.

node | Document node to be converted.
default | Value to be returned, if node could not be converted.

         # File lib/xmlsimple.rb, line 937
    937:   def node_to_text(node, default = nil)
    938:     if node.instance_of?(REXML::Element)
    939:       node.texts.map { |t| t.value }.join('')
    940:     elsif node.instance_of?(REXML::Attribute)
    941:       node.value.nil? ? default : node.value.strip
    942:     elsif node.instance_of?(REXML::Text)
    943:       node.value.strip
    944:     else
    945:       default
    946:     end
    947:   end

normalise_space(text) click to toggle source

Removes leading and trailing whitespace and sequences of whitespaces from a string.

text | String to be normalised.

         # File lib/xmlsimple.rb, line 909
    909:   def normalise_space(text)
    910:     text.strip.gsub(/\s\s+/, ' ')
    911:   end

normalize_option_names(options, known_options) click to toggle source

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.

options | Hash to be normalized.
known_options | List of known options.

         # File lib/xmlsimple.rb, line 298
    298:   def normalize_option_names(options, known_options)
    299:     return nil if options.nil?
    300:     result = Hash.new
    301:     options.each { |key, value|
    302:       lkey = key.downcase
    303:       lkey.gsub!(/_/, '')
    304:       if !known_options.member?(lkey)
    305:         raise ArgumentError, "Unrecognised option: #{lkey}."
    306:       end
    307:       result[lkey] = value
    308:     }
    309:     result
    310:   end

parse(xml_string) click to toggle source

Parses an XML string and returns the according document.

xml_string | XML string to be parsed.

The following exception may be raised:

REXML::ParseException | If the specified file is not wellformed.

         # File lib/xmlsimple.rb, line 958
    958:   def parse(xml_string)
    959:     Document.new(xml_string)
    960:   end

put_into_cache(data, filename) click to toggle source

Caches the data belonging to a certain file.

data | Data to be cached.
filename | Name of file the data was read from.

          # File lib/xmlsimple.rb, line 1010
    1010:   def put_into_cache(data, filename)
    1011:     if @options.has_key?('cache')
    1012:       @options['cache'].each { |scheme|
    1013:         case(scheme)
    1014:         when 'storable'
    1015:           @@cache.save_storable(data, filename)
    1016:         when 'mem_share'
    1017:           @@cache.save_mem_share(data, filename)
    1018:         when 'mem_copy'
    1019:           @@cache.save_mem_copy(data, filename)
    1020:         else
    1021:           raise ArgumentError, "Unsupported caching scheme: <#{scheme}>."
    1022:         end
    1023:       }
    1024:     end
    1025:   end

scalar(value) click to toggle source

Checks, if a certain value is a “scalar” value. Whatever that will be in Ruby … ;-)

value | Value to be checked.

         # File lib/xmlsimple.rb, line 868
    868:   def scalar(value)
    869:     return false if value.instance_of?(Hash) || value.instance_of?(Array)
    870:     return true
    871:   end

set_var(name, value) click to toggle source

Called when a variable definition is encountered in the XML. A variable definition looks like

       <element attrname="name">value</element>

where attrname matches the varattr setting.

         # File lib/xmlsimple.rb, line 731
    731:   def set_var(name, value)
    732:     @_var_values[name] = value
    733:   end

value_to_xml(ref, name, indent) click to toggle source

Recurses through a data structure building up and returning an XML representation of that structure as a string.

ref | Reference to the data structure to be encoded.
name | The XML tag name to be used for this item.
indent | A string of spaces for use as the current indent level.

         # File lib/xmlsimple.rb, line 754
    754:   def value_to_xml(ref, name, indent)
    755:     named = !name.nil? && name != ''
    756:     nl    = @options.has_key?('noindent') ? '' : "\n"
    757:
    758:     if !scalar(ref)
    759:       if @ancestors.member?(ref)
    760:         raise ArgumentError, "Circular data structures not supported!"
    761:       end
    762:       @ancestors << ref
    763:     else
    764:       if named
    765:         return [indent, '<', name, '>', @options['noescape'] ? ref.to_s : escape_value(ref.to_s), '</', name, '>', nl].join('')
    766:       else
    767:         return ref.to_s + nl
    768:       end
    769:     end
    770:
    771:     # Unfold hash to array if possible.
    772:     if ref.instance_of?(Hash) && !ref.empty? && !@options['keyattr'].empty? && indent != ''
    773:       ref = hash_to_array(name, ref)
    774:     end
    775:
    776:     result = []
    777:     if ref.instance_of?(Hash)
    778:       # Reintermediate grouped values if applicable.
    779:       if @options.has_key?('grouptags')
    780:         ref.each { |key, value|
    781:           if @options['grouptags'].has_key?(key)
    782:             ref[key] = { @options['grouptags'][key] => value }
    783:           end
    784:         }
    785:       end
    786:
    787:       nested = []
    788:       text_content = nil
    789:       if named
    790:         result << indent << '<' << name
    791:       end
    792:
    793:       if !ref.empty?
    794:         ref.each { |key, value|
    795:           next if !key.nil? && key.to_s[0, 1] == '-'
    796:           if value.nil?
    797:             unless @options.has_key?('suppressempty') && @options['suppressempty'].nil?
    798:               raise ArgumentError, "Use of uninitialized value!"
    799:             end
    800:             value = {}
    801:           end
    802:
    803:           # Check for the '@' attribute prefix to allow separation of attributes and elements
    804:           if @options['noattr'] ||
    805:              (@options['attrprefix'] && !(key =~ /^@(.*)/)) ||
    806:              !scalar(value)
    807:             nested << value_to_xml(value, key, indent + @options['indent'])
    808:           else
    809:             value = value.to_s
    810:             value = escape_value(value) unless @options['noescape']
    811:             if key == @options['contentkey']
    812:               text_content = value
    813:             else
    814:               result << ' ' << ($1||key) << '="' << value << '"'
    815:             end
    816:           end
    817:         }
    818:       else
    819:         text_content = ''
    820:       end
    821:
    822:       if !nested.empty? || !text_content.nil?
    823:         if named
    824:           result << '>'
    825:           if !text_content.nil?
    826:             result << text_content
    827:             nested[0].sub!(/^\s+/, '') if !nested.empty?
    828:           else
    829:             result << nl
    830:           end
    831:           if !nested.empty?
    832:             result << nested << indent
    833:           end
    834:           result << '</' << name << '>' << nl
    835:         else
    836:           result << nested
    837:         end
    838:       else
    839:         result << ' />' << nl
    840:       end
    841:     elsif ref.instance_of?(Array)
    842:       ref.each { |value|
    843:         if scalar(value)
    844:           result << indent << '<' << name << '>'
    845:           result << (@options['noescape'] ? value.to_s : escape_value(value.to_s))
    846:           result << '</' << name << '>' << nl
    847:         elsif value.instance_of?(Hash)
    848:           result << value_to_xml(value, name, indent)
    849:         else
    850:           result << indent << '<' << name << '>' << nl
    851:           result << value_to_xml(value, @options['anonymoustag'], indent + @options['indent'])
    852:           result << indent << '</' << name << '>' << nl
    853:         end
    854:       }
    855:     else
    856:       # Probably, this is obsolete.
    857:       raise ArgumentError, "Can't encode a value of type: #{ref.type}."
    858:     end
    859:     @ancestors.pop if !scalar(ref)
    860:     result.join('')
    861:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.