In Files

Parent

Namespace

Included Modules

Class Index [+]

Quicksearch

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.