xml-simple 1.0.11 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/xmlsimple.rb +144 -103
  3. metadata +51 -40
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 83fdfe764b21f66e184a245f9f908d2ed9678edd6d0734a33cac93030449c324
4
+ data.tar.gz: ecd9ac1ed12a0fb03f2b8fee924db65ec844dffda64f9553b76a626b2532635a
5
+ SHA512:
6
+ metadata.gz: 652f1cbb3ef139e5450cdd2ad01fc4a22e23ec3174bd3d88c58b973f1c5c955673a365bbaa3e3c910ad60c190994e3e0e88fd4678af69d5981aadd2b0ecb019d
7
+ data.tar.gz: 40e7a0e3e6b0a42d178e8f6b782aca2e8a6d65ce87ab8aa06953d7dfe41b4ce115793018df2bab0b6238298d1c35ccdaa2fee9a0ea46ac927f2d2238d2f0146d
data/lib/xmlsimple.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # = XmlSimple
2
2
  #
3
3
  # Author:: Maik Schmidt <contact@maik-schmidt.de>
4
- # Copyright:: Copyright (c) 2003-2006 Maik Schmidt
4
+ # Copyright:: Copyright (c) 2003-2021 Maik Schmidt
5
5
  # License:: Distributes under the same terms as Ruby.
6
6
  #
7
7
  require 'rexml/document'
@@ -11,7 +11,7 @@ require 'stringio'
11
11
  class XmlSimple
12
12
  include REXML
13
13
 
14
- @@VERSION = '1.0.11'
14
+ @@VERSION = '1.1.9'
15
15
 
16
16
  # A simple cache for XML documents that were already transformed
17
17
  # by xml_in.
@@ -23,7 +23,7 @@ class XmlSimple
23
23
  end
24
24
 
25
25
  # Saves a data structure into a file.
26
- #
26
+ #
27
27
  # data::
28
28
  # Data structure to be saved.
29
29
  # filename::
@@ -121,12 +121,12 @@ class XmlSimple
121
121
  # Create a "global" cache.
122
122
  @@cache = Cache.new
123
123
 
124
- # Creates and intializes a new XmlSimple object.
125
- #
124
+ # Creates and initializes a new XmlSimple object.
125
+ #
126
126
  # defaults::
127
127
  # Default values for options.
128
128
  def initialize(defaults = nil)
129
- unless defaults.nil? || defaults.instance_of?(Hash)
129
+ unless defaults.nil? || defaults.is_a?(Hash)
130
130
  raise ArgumentError, "Options have to be a Hash."
131
131
  end
132
132
  @default_options = normalize_option_names(defaults, (KNOWN_OPTIONS['in'] + KNOWN_OPTIONS['out']).uniq)
@@ -143,7 +143,7 @@ class XmlSimple
143
143
  # - filename: Tries to load and parse filename.
144
144
  # - IO object: Reads from object until EOF is detected and parses result.
145
145
  # - XML string: Parses string.
146
- #
146
+ #
147
147
  # options::
148
148
  # Options to be used.
149
149
  def xml_in(string = nil, options = nil)
@@ -151,7 +151,7 @@ class XmlSimple
151
151
 
152
152
  # If no XML string or filename was supplied look for scriptname.xml.
153
153
  if string.nil?
154
- string = File::basename($0)
154
+ string = File::basename($0).dup
155
155
  string.sub!(/\.[^.]+$/, '')
156
156
  string += '.xml'
157
157
 
@@ -159,11 +159,11 @@ class XmlSimple
159
159
  @options['searchpath'].unshift(directory) unless directory.nil?
160
160
  end
161
161
 
162
- if string.instance_of?(String)
162
+ if string.is_a?(String)
163
163
  if string =~ /<.*?>/m
164
164
  @doc = parse(string)
165
165
  elsif string == '-'
166
- @doc = parse($stdin.readlines.to_s)
166
+ @doc = parse($stdin.read)
167
167
  else
168
168
  filename = find_xml_file(string, @options['searchpath'])
169
169
 
@@ -182,13 +182,13 @@ class XmlSimple
182
182
  return content if content
183
183
  }
184
184
  end
185
-
185
+
186
186
  @doc = load_xml_file(filename)
187
187
  end
188
- elsif string.kind_of?(IO) || string.kind_of?(StringIO)
189
- @doc = parse(string.readlines.to_s)
188
+ elsif string.respond_to?(:read)
189
+ @doc = parse(string.read)
190
190
  else
191
- raise ArgumentError, "Could not parse object of type: <#{string.type}>."
191
+ raise ArgumentError, "Could not parse object of type: <#{string.class}>."
192
192
  end
193
193
 
194
194
  result = collapse(@doc.root)
@@ -202,7 +202,7 @@ class XmlSimple
202
202
  xml_simple = XmlSimple.new
203
203
  xml_simple.xml_in(string, options)
204
204
  end
205
-
205
+
206
206
  # Converts a data structure into an XML document.
207
207
  #
208
208
  # ref::
@@ -211,7 +211,7 @@ class XmlSimple
211
211
  # Options to be used.
212
212
  def xml_out(ref, options = nil)
213
213
  handle_options('out', options)
214
- if ref.instance_of?(Array)
214
+ if ref.is_a?(Array)
215
215
  ref = { @options['anonymoustag'] => ref }
216
216
  end
217
217
 
@@ -222,7 +222,7 @@ class XmlSimple
222
222
  @options['rootname'] = keys[0]
223
223
  end
224
224
  elsif @options['rootname'] == ''
225
- if ref.instance_of?(Hash)
225
+ if ref.is_a?(Hash)
226
226
  refsave = ref
227
227
  ref = {}
228
228
  refsave.each { |key, value|
@@ -258,21 +258,21 @@ class XmlSimple
258
258
  xml_simple = XmlSimple.new
259
259
  xml_simple.xml_out(hash, options)
260
260
  end
261
-
261
+
262
262
  private
263
263
 
264
264
  # Declare options that are valid for xml_in and xml_out.
265
265
  KNOWN_OPTIONS = {
266
266
  'in' => %w(
267
- keyattr keeproot forcecontent contentkey noattr
268
- searchpath forcearray suppressempty anonymoustag
269
- cache grouptags normalisespace normalizespace
270
- variables varattr keytosymbol
267
+ keyattr keeproot forcecontent contentkey noattr searchpath
268
+ forcearray suppressempty anonymoustag cache grouptags
269
+ normalisespace normalizespace variables varattr keytosymbol
270
+ attrtosymbol attrprefix conversions kebabtosnakecase
271
271
  ),
272
272
  'out' => %w(
273
273
  keyattr keeproot contentkey noattr rootname
274
274
  xmldeclaration outputfile noescape suppressempty
275
- anonymoustag indent grouptags noindent
275
+ anonymoustag indent grouptags noindent attrprefix selfclose
276
276
  )
277
277
  }
278
278
 
@@ -285,11 +285,13 @@ class XmlSimple
285
285
  DEF_FORCE_ARRAY = true
286
286
  DEF_INDENTATION = ' '
287
287
  DEF_KEY_TO_SYMBOL = false
288
-
288
+ DEF_ATTR_TO_SYMBOL = false
289
+ DEF_KEBAB_TO_SNAKE = false
290
+
289
291
  # Normalizes option names in a hash, i.e., turns all
290
292
  # characters to lower case and removes all underscores.
291
- # Additionally, this method checks, if an unknown option
292
- # was used and raises an according exception.
293
+ # Additionally, this method checks if an unknown option
294
+ # was used, and raises an according exception.
293
295
  #
294
296
  # options::
295
297
  # Hash to be normalized.
@@ -299,18 +301,17 @@ class XmlSimple
299
301
  return nil if options.nil?
300
302
  result = Hash.new
301
303
  options.each { |key, value|
302
- lkey = key.downcase
303
- lkey.gsub!(/_/, '')
304
+ lkey = key.to_s.downcase.gsub(/_/, '')
304
305
  if !known_options.member?(lkey)
305
- raise ArgumentError, "Unrecognised option: #{lkey}."
306
+ raise ArgumentError, "Unrecognized option: #{lkey}."
306
307
  end
307
308
  result[lkey] = value
308
309
  }
309
310
  result
310
311
  end
311
-
312
+
312
313
  # Merges a set of options with the default options.
313
- #
314
+ #
314
315
  # direction::
315
316
  # 'in': If options should be handled for xml_in.
316
317
  # 'out': If options should be handled for xml_out.
@@ -319,7 +320,7 @@ class XmlSimple
319
320
  def handle_options(direction, options)
320
321
  @options = options || Hash.new
321
322
 
322
- raise ArgumentError, "Options must be a Hash!" unless @options.instance_of?(Hash)
323
+ raise ArgumentError, "Options must be a Hash!" unless @options.is_a?(Hash)
323
324
 
324
325
  unless KNOWN_OPTIONS.has_key?(direction)
325
326
  raise ArgumentError, "Unknown direction: <#{direction}>."
@@ -354,6 +355,8 @@ class XmlSimple
354
355
 
355
356
  @options['keytosymbol'] = DEF_KEY_TO_SYMBOL unless @options.has_key?('keytosymbol')
356
357
 
358
+ @options['attrtosymbol'] = DEF_ATTR_TO_SYMBOL unless @options.has_key?('attrtosymbol')
359
+
357
360
  if @options.has_key?('contentkey')
358
361
  if @options['contentkey'] =~ /^-(.*)$/
359
362
  @options['contentkey'] = $1
@@ -369,7 +372,7 @@ class XmlSimple
369
372
  @options['normalisespace'] = 0 if @options['normalisespace'].nil?
370
373
 
371
374
  if @options.has_key?('searchpath')
372
- unless @options['searchpath'].instance_of?(Array)
375
+ unless @options['searchpath'].is_a?(Array)
373
376
  @options['searchpath'] = [ @options['searchpath'] ]
374
377
  end
375
378
  else
@@ -394,13 +397,13 @@ class XmlSimple
394
397
  if !scalar(@options['keyattr'])
395
398
  # Convert keyattr => { elem => '+attr' }
396
399
  # to keyattr => { elem => ['attr', '+'] }
397
- if @options['keyattr'].instance_of?(Hash)
400
+ if @options['keyattr'].is_a?(Hash)
398
401
  @options['keyattr'].each { |key, value|
399
402
  if value =~ /^([-+])?(.*)$/
400
403
  @options['keyattr'][key] = [$2, $1 ? $1 : '']
401
404
  end
402
405
  }
403
- elsif !@options['keyattr'].instance_of?(Array)
406
+ elsif !@options['keyattr'].is_a?(Array)
404
407
  raise ArgumentError, "'keyattr' must be String, Hash, or Array!"
405
408
  end
406
409
  else
@@ -411,17 +414,17 @@ class XmlSimple
411
414
  end
412
415
 
413
416
  if @options.has_key?('forcearray')
414
- if @options['forcearray'].instance_of?(Regexp)
417
+ if @options['forcearray'].is_a?(Regexp)
415
418
  @options['forcearray'] = [ @options['forcearray'] ]
416
419
  end
417
420
 
418
- if @options['forcearray'].instance_of?(Array)
421
+ if @options['forcearray'].is_a?(Array)
419
422
  force_list = @options['forcearray']
420
423
  unless force_list.empty?
421
424
  @options['forcearray'] = {}
422
425
  force_list.each { |tag|
423
- if tag.instance_of?(Regexp)
424
- unless @options['forcearray']['_regex'].instance_of?(Array)
426
+ if tag.is_a?(Regexp)
427
+ unless @options['forcearray']['_regex'].is_a?(Array)
425
428
  @options['forcearray']['_regex'] = []
426
429
  end
427
430
  @options['forcearray']['_regex'] << tag
@@ -439,11 +442,11 @@ class XmlSimple
439
442
  @options['forcearray'] = DEF_FORCE_ARRAY
440
443
  end
441
444
 
442
- if @options.has_key?('grouptags') && !@options['grouptags'].instance_of?(Hash)
445
+ if @options.has_key?('grouptags') && !@options['grouptags'].is_a?(Hash)
443
446
  raise ArgumentError, "Illegal value for 'GroupTags' option - expected a Hash."
444
447
  end
445
448
 
446
- if @options.has_key?('variables') && !@options['variables'].instance_of?(Hash)
449
+ if @options.has_key?('variables') && !@options['variables'].is_a?(Hash)
447
450
  raise ArgumentError, "Illegal value for 'Variables' option - expected a Hash."
448
451
  end
449
452
 
@@ -452,6 +455,8 @@ class XmlSimple
452
455
  elsif @options.has_key?('varattr')
453
456
  @_var_values = {}
454
457
  end
458
+
459
+ @options['kebabtosnakecase'] = DEF_KEBAB_TO_SNAKE unless @options.has_key?('kebabtosnakecase')
455
460
  end
456
461
 
457
462
  # Actually converts an XML document element into a data structure.
@@ -480,7 +485,7 @@ class XmlSimple
480
485
  result[@options['contentkey']] = content
481
486
  end
482
487
  elsif element.has_text? # i.e. it has only text.
483
- return collapse_text_node(result, element)
488
+ return collapse_text_node(result, element) # calls merge, which converts
484
489
  end
485
490
 
486
491
  # Turn Arrays into Hashes if key fields present.
@@ -489,18 +494,21 @@ class XmlSimple
489
494
  # Disintermediate grouped tags.
490
495
  if @options.has_key?('grouptags')
491
496
  result.each { |key, value|
492
- next unless (value.instance_of?(Hash) && (value.size == 1))
497
+ # In results, key should already be converted
498
+ raise("Unconverted key '#{key}' found. Should be '#{kebab_to_snake_case key}'.") if (key != kebab_to_snake_case(key))
499
+ next unless (value.is_a?(Hash) && (value.size == 1))
493
500
  child_key, child_value = value.to_a[0]
501
+ child_key = kebab_to_snake_case child_key # todo test whether necessary
494
502
  if @options['grouptags'][key] == child_key
495
503
  result[key] = child_value
496
504
  end
497
505
  }
498
506
  end
499
-
500
- # Fold Hases containing a single anonymous Array up into just the Array.
501
- if count == 1
507
+
508
+ # Fold Hashes containing a single anonymous Array up into just the Array.
509
+ if count == 1
502
510
  anonymoustag = @options['anonymoustag']
503
- if result.has_key?(anonymoustag) && result[anonymoustag].instance_of?(Array)
511
+ if result.has_key?(anonymoustag) && result[anonymoustag].is_a?(Array)
504
512
  return result[anonymoustag]
505
513
  end
506
514
  end
@@ -538,16 +546,17 @@ class XmlSimple
538
546
  end
539
547
 
540
548
  # Folds all arrays in a Hash.
541
- #
549
+ #
542
550
  # hash::
543
551
  # Hash to be folded.
544
552
  def fold_arrays(hash)
545
553
  fold_amount = 0
546
554
  keyattr = @options['keyattr']
547
- if (keyattr.instance_of?(Array) || keyattr.instance_of?(Hash))
555
+ if (keyattr.is_a?(Array) || keyattr.is_a?(Hash))
548
556
  hash.each { |key, value|
549
- if value.instance_of?(Array)
550
- if keyattr.instance_of?(Array)
557
+ key = kebab_to_snake_case key
558
+ if value.is_a?(Array)
559
+ if keyattr.is_a?(Array)
551
560
  hash[key] = fold_array(value)
552
561
  else
553
562
  hash[key] = fold_array_by_name(key, value)
@@ -568,13 +577,13 @@ class XmlSimple
568
577
  def fold_array(array)
569
578
  hash = Hash.new
570
579
  array.each { |x|
571
- return array unless x.instance_of?(Hash)
580
+ return array unless x.is_a?(Hash)
572
581
  key_matched = false
573
582
  @options['keyattr'].each { |key|
574
583
  if x.has_key?(key)
575
584
  key_matched = true
576
585
  value = x[key]
577
- return array if value.instance_of?(Hash) || value.instance_of?(Array)
586
+ return array if value.is_a?(Hash) || value.is_a?(Array)
578
587
  value = normalise_space(value) if @options['normalisespace'] == 1
579
588
  x.delete(key)
580
589
  hash[value] = x
@@ -586,7 +595,7 @@ class XmlSimple
586
595
  hash = collapse_content(hash) if @options['collapseagain']
587
596
  hash
588
597
  end
589
-
598
+
590
599
  # Folds an Array to a Hash, if possible. Folding happens
591
600
  # according to the content of keyattr, which has to be
592
601
  # a Hash.
@@ -601,9 +610,9 @@ class XmlSimple
601
610
 
602
611
  hash = Hash.new
603
612
  array.each { |x|
604
- if x.instance_of?(Hash) && x.has_key?(key)
613
+ if x.is_a?(Hash) && x.has_key?(key)
605
614
  value = x[key]
606
- return array if value.instance_of?(Hash) || value.instance_of?(Array)
615
+ return array if value.is_a?(Hash) || value.is_a?(Array)
607
616
  value = normalise_space(value) if @options['normalisespace'] == 1
608
617
  hash[value] = x
609
618
  hash[value]["-#{key}"] = hash[value][key] if flag == '-'
@@ -624,12 +633,12 @@ class XmlSimple
624
633
  def collapse_content(hash)
625
634
  content_key = @options['contentkey']
626
635
  hash.each_value { |value|
627
- return hash unless value.instance_of?(Hash) && value.size == 1 && value.has_key?(content_key)
636
+ return hash unless value.is_a?(Hash) && value.size == 1 && value.has_key?(content_key)
628
637
  hash.each_key { |key| hash[key] = hash[key][content_key] }
629
638
  }
630
639
  hash
631
640
  end
632
-
641
+
633
642
  # Adds a new key/value pair to an existing Hash. If the key to be added
634
643
  # does already exist and the existing value associated with key is not
635
644
  # an Array, it will be converted into an Array. Then the new value is
@@ -642,37 +651,42 @@ class XmlSimple
642
651
  # value::
643
652
  # Value to be associated with key.
644
653
  def merge(hash, key, value)
645
- if value.instance_of?(String)
654
+ key = kebab_to_snake_case key
655
+ if value.is_a?(String)
646
656
  value = normalise_space(value) if @options['normalisespace'] == 2
647
657
 
658
+ if conv = @options['conversions'] and conv = conv.find {|c,_| c.match(key)} and conv = conv.at(1)
659
+ value = conv.call(value)
660
+ end
661
+
648
662
  # do variable substitutions
649
663
  unless @_var_values.nil? || @_var_values.empty?
650
664
  value.gsub!(/\$\{(\w+)\}/) { |x| get_var($1) }
651
665
  end
652
-
666
+
653
667
  # look for variable definitions
654
668
  if @options.has_key?('varattr')
655
- varattr = @options['varattr']
669
+ varattr = kebab_to_snake_case @options['varattr']
656
670
  if hash.has_key?(varattr)
657
671
  set_var(hash[varattr], value)
658
672
  end
659
673
  end
660
674
  end
661
-
675
+
662
676
  #patch for converting keys to symbols
663
677
  if @options.has_key?('keytosymbol')
664
678
  if @options['keytosymbol'] == true
665
679
  key = key.to_s.downcase.to_sym
666
680
  end
667
681
  end
668
-
682
+
669
683
  if hash.has_key?(key)
670
- if hash[key].instance_of?(Array)
684
+ if hash[key].is_a?(Array)
671
685
  hash[key] << value
672
686
  else
673
687
  hash[key] = [ hash[key], value ]
674
688
  end
675
- elsif value.instance_of?(Array) # Handle anonymous arrays.
689
+ elsif value.is_a?(Array) # Handle anonymous arrays.
676
690
  hash[key] = [ value ]
677
691
  else
678
692
  if force_array?(key)
@@ -683,21 +697,21 @@ class XmlSimple
683
697
  end
684
698
  hash
685
699
  end
686
-
700
+
687
701
  # Checks, if the 'forcearray' option has to be used for
688
702
  # a certain key.
689
703
  def force_array?(key)
690
704
  return false if key == @options['contentkey']
691
705
  return true if @options['forcearray'] == true
692
706
  forcearray = @options['forcearray']
693
- if forcearray.instance_of?(Hash)
694
- return true if forcearray.has_key?(key)
707
+ if forcearray.is_a?(Hash)
708
+ return true if forcearray.has_key?(key)
695
709
  return false unless forcearray.has_key?('_regex')
696
710
  forcearray['_regex'].each { |x| return true if key =~ x }
697
711
  end
698
712
  return false
699
713
  end
700
-
714
+
701
715
  # Converts the attributes array of a document node into a Hash.
702
716
  # Returns an empty Hash, if node has no attributes.
703
717
  #
@@ -705,21 +719,28 @@ class XmlSimple
705
719
  # Document node to extract attributes from.
706
720
  def get_attributes(node)
707
721
  attributes = {}
708
- node.attributes.each { |n,v| attributes[n] = v }
722
+ if @options['attrprefix']
723
+ node.attributes.each { |n,v| attributes["@" + kebab_to_snake_case(n)] = v }
724
+ elsif @options.has_key?('attrtosymbol') and @options['attrtosymbol'] == true
725
+ #patch for converting attribute names to symbols
726
+ node.attributes.each { |n,v| attributes[kebab_to_snake_case(n).to_sym] = v }
727
+ else
728
+ node.attributes.each { |n,v| attributes[kebab_to_snake_case(n)] = v }
729
+ end
730
+
709
731
  attributes
710
732
  end
711
-
733
+
712
734
  # Determines, if a document element has mixed content.
713
735
  #
714
736
  # element::
715
737
  # Document element to be checked.
716
738
  def has_mixed_content?(element)
717
- if element.has_text? && element.has_elements?
718
- return true if element.texts.join('') !~ /^\s*$/s
719
- end
720
- false
739
+ element.has_text? &&
740
+ element.has_elements? &&
741
+ !element.texts.join('').strip.empty?
721
742
  end
722
-
743
+
723
744
  # Called when a variable definition is encountered in the XML.
724
745
  # A variable definition looks like
725
746
  # <element attrname="name">value</element>
@@ -737,7 +758,7 @@ class XmlSimple
737
758
  return "${#{name}}"
738
759
  end
739
760
  end
740
-
761
+
741
762
  # Recurses through a data structure building up and returning an
742
763
  # XML representation of that structure as a string.
743
764
  #
@@ -765,12 +786,12 @@ class XmlSimple
765
786
  end
766
787
 
767
788
  # Unfold hash to array if possible.
768
- if ref.instance_of?(Hash) && !ref.empty? && !@options['keyattr'].empty? && indent != ''
789
+ if ref.is_a?(Hash) && !ref.empty? && !@options['keyattr'].empty? && indent != ''
769
790
  ref = hash_to_array(name, ref)
770
791
  end
771
792
 
772
793
  result = []
773
- if ref.instance_of?(Hash)
794
+ if ref.is_a?(Hash)
774
795
  # Reintermediate grouped values if applicable.
775
796
  if @options.has_key?('grouptags')
776
797
  ref.each { |key, value|
@@ -779,7 +800,7 @@ class XmlSimple
779
800
  end
780
801
  }
781
802
  end
782
-
803
+
783
804
  nested = []
784
805
  text_content = nil
785
806
  if named
@@ -788,7 +809,7 @@ class XmlSimple
788
809
 
789
810
  if !ref.empty?
790
811
  ref.each { |key, value|
791
- next if !key.nil? && key[0, 1] == '-'
812
+ next if !key.nil? && key.to_s[0, 1] == '-'
792
813
  if value.nil?
793
814
  unless @options.has_key?('suppressempty') && @options['suppressempty'].nil?
794
815
  raise ArgumentError, "Use of uninitialized value!"
@@ -796,7 +817,13 @@ class XmlSimple
796
817
  value = {}
797
818
  end
798
819
 
799
- if !scalar(value) || @options['noattr']
820
+ # Check for the '@' attribute prefix to allow separation of attributes and elements
821
+
822
+ if (@options['noattr'] ||
823
+ (@options['attrprefix'] && !(key =~ /^@(.*)/)) ||
824
+ !scalar(value)
825
+ ) &&
826
+ key != @options['contentkey']
800
827
  nested << value_to_xml(value, key, indent + @options['indent'])
801
828
  else
802
829
  value = value.to_s
@@ -804,11 +831,11 @@ class XmlSimple
804
831
  if key == @options['contentkey']
805
832
  text_content = value
806
833
  else
807
- result << ' ' << key << '="' << value << '"'
834
+ result << ' ' << ($1||key) << '="' << value << '"'
808
835
  end
809
836
  end
810
837
  }
811
- else
838
+ elsif !@options['selfclose']
812
839
  text_content = ''
813
840
  end
814
841
 
@@ -831,13 +858,13 @@ class XmlSimple
831
858
  else
832
859
  result << ' />' << nl
833
860
  end
834
- elsif ref.instance_of?(Array)
861
+ elsif ref.is_a?(Array)
835
862
  ref.each { |value|
836
863
  if scalar(value)
837
864
  result << indent << '<' << name << '>'
838
865
  result << (@options['noescape'] ? value.to_s : escape_value(value.to_s))
839
866
  result << '</' << name << '>' << nl
840
- elsif value.instance_of?(Hash)
867
+ elsif value.is_a?(Hash)
841
868
  result << value_to_xml(value, name, indent)
842
869
  else
843
870
  result << indent << '<' << name << '>' << nl
@@ -852,31 +879,31 @@ class XmlSimple
852
879
  @ancestors.pop if !scalar(ref)
853
880
  result.join('')
854
881
  end
855
-
882
+
856
883
  # Checks, if a certain value is a "scalar" value. Whatever
857
884
  # that will be in Ruby ... ;-)
858
- #
885
+ #
859
886
  # value::
860
887
  # Value to be checked.
861
888
  def scalar(value)
862
- return false if value.instance_of?(Hash) || value.instance_of?(Array)
889
+ return false if value.is_a?(Hash) || value.is_a?(Array)
863
890
  return true
864
891
  end
865
892
 
866
893
  # Attempts to unfold a hash of hashes into an array of hashes. Returns
867
894
  # a reference to th array on success or the original hash, if unfolding
868
895
  # is not possible.
869
- #
896
+ #
870
897
  # parent::
871
- #
898
+ #
872
899
  # hashref::
873
900
  # Reference to the hash to be unfolded.
874
901
  def hash_to_array(parent, hashref)
875
902
  arrayref = []
876
903
  hashref.each { |key, value|
877
- return hashref unless value.instance_of?(Hash)
904
+ return hashref unless value.is_a?(Hash)
878
905
 
879
- if @options['keyattr'].instance_of?(Hash)
906
+ if @options['keyattr'].is_a?(Hash)
880
907
  return hashref unless @options['keyattr'].has_key?(parent)
881
908
  arrayref << { @options['keyattr'][parent][0] => key }.update(value)
882
909
  else
@@ -885,7 +912,7 @@ class XmlSimple
885
912
  }
886
913
  arrayref
887
914
  end
888
-
915
+
889
916
  # Replaces XML markup characters by their external entities.
890
917
  #
891
918
  # data::
@@ -893,7 +920,7 @@ class XmlSimple
893
920
  def escape_value(data)
894
921
  Text::normalize(data)
895
922
  end
896
-
923
+
897
924
  # Removes leading and trailing whitespace and sequences of
898
925
  # whitespaces from a string.
899
926
  #
@@ -918,7 +945,7 @@ class XmlSimple
918
945
  return value.nil?
919
946
  end
920
947
  end
921
-
948
+
922
949
  # Converts a document node into a String.
923
950
  # If the node could not be converted into a String
924
951
  # for any reason, default will be returned.
@@ -928,11 +955,11 @@ class XmlSimple
928
955
  # default::
929
956
  # Value to be returned, if node could not be converted.
930
957
  def node_to_text(node, default = nil)
931
- if node.instance_of?(REXML::Element)
958
+ if node.is_a?(REXML::Element)
932
959
  node.texts.map { |t| t.value }.join('')
933
- elsif node.instance_of?(REXML::Attribute)
960
+ elsif node.is_a?(REXML::Attribute)
934
961
  node.value.nil? ? default : node.value.strip
935
- elsif node.instance_of?(REXML::Text)
962
+ elsif node.is_a?(REXML::Text)
936
963
  node.value.strip
937
964
  else
938
965
  default
@@ -951,7 +978,7 @@ class XmlSimple
951
978
  def parse(xml_string)
952
979
  Document.new(xml_string)
953
980
  end
954
-
981
+
955
982
  # Searches in a list of paths for a certain file. Returns
956
983
  # the full path to the file, if it could be found. Otherwise,
957
984
  # an exception will be raised.
@@ -978,20 +1005,20 @@ class XmlSimple
978
1005
  end
979
1006
  raise ArgumentError, "Could not find <#{filename}> in <#{searchpath.join(':')}>"
980
1007
  end
981
-
1008
+
982
1009
  # Loads and parses an XML configuration file.
983
1010
  #
984
1011
  # filename::
985
1012
  # Name of the configuration file to be loaded.
986
1013
  #
987
1014
  # The following exceptions may be raised:
988
- #
1015
+ #
989
1016
  # Errno::ENOENT::
990
1017
  # If the specified file does not exist.
991
1018
  # REXML::ParseException::
992
1019
  # If the specified file is not wellformed.
993
1020
  def load_xml_file(filename)
994
- parse(File.readlines(filename).to_s)
1021
+ parse(IO::read(filename))
995
1022
  end
996
1023
 
997
1024
  # Caches the data belonging to a certain file.
@@ -1016,6 +1043,20 @@ class XmlSimple
1016
1043
  }
1017
1044
  end
1018
1045
  end
1046
+
1047
+ # Substitutes underscores for hyphens if the KebabToSnakeCase option is selected. For when you don't
1048
+ # want to refer to keys by hash[:'my-key'] but instead as hash[:my_key]
1049
+ #
1050
+ # key::
1051
+ # Key to be converted.
1052
+ def kebab_to_snake_case(key)
1053
+ return key unless (@options['kebabtosnakecase'])
1054
+
1055
+ is_symbol = key.is_a? Symbol
1056
+ key = key.to_s.gsub(/-/, '_')
1057
+ key = key.to_sym if is_symbol
1058
+ key
1059
+ end
1019
1060
  end
1020
1061
 
1021
1062
  # vim:sw=2
metadata CHANGED
@@ -1,46 +1,57 @@
1
- --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
3
- specification_version: 1
1
+ --- !ruby/object:Gem::Specification
4
2
  name: xml-simple
5
- version: !ruby/object:Gem::Version
6
- version: 1.0.11
7
- date: 2007-03-12 00:00:00 +01:00
8
- summary: A very simple API for XML processing.
9
- require_paths:
10
- - lib
11
- email: contact@maik-schmidt.de
12
- homepage: http://xml-simple.rubyforge.org
13
- rubyforge_project: xml-simple
14
- description:
15
- autorequire: xmlsimple
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: false
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.9
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
- authors:
6
+ authors:
30
7
  - Maik Schmidt
31
- files:
32
- - lib/xmlsimple.rb
33
- test_files: []
34
-
35
- rdoc_options: []
36
-
37
- extra_rdoc_files: []
38
-
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rexml
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description:
28
+ email: contact@maik-schmidt.de
39
29
  executables: []
40
-
41
30
  extensions: []
42
-
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/xmlsimple.rb
34
+ homepage: https://github.com/maik/xml-simple
35
+ licenses:
36
+ - MIT
37
+ metadata: {}
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
43
52
  requirements: []
44
-
45
- dependencies: []
46
-
53
+ rubygems_version: 3.1.2
54
+ signing_key:
55
+ specification_version: 4
56
+ summary: A simple API for XML processing.
57
+ test_files: []