xml-simple 1.0.11 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []