libis-tools 1.0.5-java
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.
- checksums.yaml +7 -0
 - data/.coveralls.yml +2 -0
 - data/.gitignore +16 -0
 - data/.rspec +2 -0
 - data/.travis.yml +40 -0
 - data/Gemfile +7 -0
 - data/README.md +202 -0
 - data/Rakefile +11 -0
 - data/bin/libis_tool +5 -0
 - data/lib/libis-tools.rb +1 -0
 - data/lib/libis/tools.rb +25 -0
 - data/lib/libis/tools/assert.rb +52 -0
 - data/lib/libis/tools/checksum.rb +106 -0
 - data/lib/libis/tools/cli/cli_helper.rb +189 -0
 - data/lib/libis/tools/cli/reorg.rb +416 -0
 - data/lib/libis/tools/command.rb +133 -0
 - data/lib/libis/tools/command_line.rb +23 -0
 - data/lib/libis/tools/config.rb +147 -0
 - data/lib/libis/tools/config_file.rb +85 -0
 - data/lib/libis/tools/csv.rb +38 -0
 - data/lib/libis/tools/deep_struct.rb +71 -0
 - data/lib/libis/tools/extend/array.rb +16 -0
 - data/lib/libis/tools/extend/empty.rb +7 -0
 - data/lib/libis/tools/extend/hash.rb +147 -0
 - data/lib/libis/tools/extend/kernel.rb +25 -0
 - data/lib/libis/tools/extend/ostruct.rb +3 -0
 - data/lib/libis/tools/extend/roo.rb +91 -0
 - data/lib/libis/tools/extend/string.rb +94 -0
 - data/lib/libis/tools/extend/struct.rb +29 -0
 - data/lib/libis/tools/extend/symbol.rb +8 -0
 - data/lib/libis/tools/logger.rb +130 -0
 - data/lib/libis/tools/mets_dnx.rb +61 -0
 - data/lib/libis/tools/mets_file.rb +504 -0
 - data/lib/libis/tools/mets_objects.rb +547 -0
 - data/lib/libis/tools/parameter.rb +372 -0
 - data/lib/libis/tools/spreadsheet.rb +196 -0
 - data/lib/libis/tools/temp_file.rb +42 -0
 - data/lib/libis/tools/thread_safe.rb +31 -0
 - data/lib/libis/tools/version.rb +5 -0
 - data/lib/libis/tools/xml_document.rb +583 -0
 - data/libis-tools.gemspec +55 -0
 - data/spec/assert_spec.rb +65 -0
 - data/spec/checksum_spec.rb +68 -0
 - data/spec/command_spec.rb +90 -0
 - data/spec/config_file_spec.rb +83 -0
 - data/spec/config_spec.rb +113 -0
 - data/spec/csv_spec.rb +159 -0
 - data/spec/data/test-headers.csv +2 -0
 - data/spec/data/test-headers.tsv +2 -0
 - data/spec/data/test-noheaders.csv +1 -0
 - data/spec/data/test-noheaders.tsv +1 -0
 - data/spec/data/test.data +9 -0
 - data/spec/data/test.xlsx +0 -0
 - data/spec/data/test.xml +8 -0
 - data/spec/data/test.yml +2 -0
 - data/spec/data/test_config.yml +15 -0
 - data/spec/deep_struct_spec.rb +138 -0
 - data/spec/logger_spec.rb +165 -0
 - data/spec/mets_file_spec.rb +223 -0
 - data/spec/parameter_container_spec.rb +152 -0
 - data/spec/parameter_spec.rb +148 -0
 - data/spec/spec_helper.rb +29 -0
 - data/spec/spreadsheet_spec.rb +1820 -0
 - data/spec/temp_file_spec.rb +76 -0
 - data/spec/test.xsd +20 -0
 - data/spec/thread_safe_spec.rb +64 -0
 - data/spec/xmldocument_spec.rb +421 -0
 - data/test/test_helper.rb +7 -0
 - data/test/webservices/test_ca_item_info.rb +59 -0
 - data/test/webservices/test_ca_search.rb +35 -0
 - metadata +437 -0
 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'libis/tools/extend/empty'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Libis
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Tools
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                module TempFile
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def self.dir
         
     | 
| 
      
 9 
     | 
    
         
            +
                    Dir.tmpdir
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def self.name(prefix = '', suffix = '', _dir = nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    _dir ||= dir
         
     | 
| 
      
 14 
     | 
    
         
            +
                    t = Time.now.strftime('%Y%m%d')
         
     | 
| 
      
 15 
     | 
    
         
            +
                    t = '_' + t unless prefix.empty?
         
     | 
| 
      
 16 
     | 
    
         
            +
                    File.join(_dir, "#{prefix}#{t}_#{$$}_#{rand(0x100000000).to_s(36)}#{suffix}".freeze)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def self.file(prefix = '', suffix = '', dir = nil)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    f = File.open(name(prefix, suffix, dir), 'w')
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    def f.unlink
         
     | 
| 
      
 23 
     | 
    
         
            +
                      File.unlink self
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    def f.delete
         
     | 
| 
      
 27 
     | 
    
         
            +
                      File.delete self
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    if block_given?
         
     | 
| 
      
 31 
     | 
    
         
            +
                      x = yield(f)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      f.close
         
     | 
| 
      
 33 
     | 
    
         
            +
                      f.delete
         
     | 
| 
      
 34 
     | 
    
         
            +
                      return x
         
     | 
| 
      
 35 
     | 
    
         
            +
                    else
         
     | 
| 
      
 36 
     | 
    
         
            +
                      return f
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'monitor'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Libis
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Tools
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # Module to safely create a mutex for creating thread safe classes.
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # Usage: include this module in a class or extend a module with this one.
         
     | 
| 
      
 9 
     | 
    
         
            +
                module ThreadSafe
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  # Access the instance mutex
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def mutex
         
     | 
| 
      
 13 
     | 
    
         
            +
                    self.class.class_mutex.synchronize do
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @mutex ||= Monitor.new
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  # @!visibility private
         
     | 
| 
      
 19 
     | 
    
         
            +
                  module MutexCreator
         
     | 
| 
      
 20 
     | 
    
         
            +
                    attr_accessor :class_mutex
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  # @!visibility private
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def self.included(klass)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    klass.extend(MutexCreator)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    # noinspection RubyResolve
         
     | 
| 
      
 27 
     | 
    
         
            +
                    klass.class_mutex = Monitor.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,583 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'gyoku'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'nori'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Libis
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Tools
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                # noinspection RubyTooManyMethodsInspection
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                # This class embodies most used features of Nokogiri, Nori and Gyoku in one convenience class. The Nokogiri document
         
     | 
| 
      
 13 
     | 
    
         
            +
                # is stored in the class variable 'document' and can be accessed and manipulated directly - if required.
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                # In the examples we assume the following XML code:
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                #     <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 18 
     | 
    
         
            +
                #     <patron>
         
     | 
| 
      
 19 
     | 
    
         
            +
                #       <name>Harry Potter</name>
         
     | 
| 
      
 20 
     | 
    
         
            +
                #       <barcode library='Hogwarts Library'>1234567890</barcode>
         
     | 
| 
      
 21 
     | 
    
         
            +
                #       <access_level>student</access_level>
         
     | 
| 
      
 22 
     | 
    
         
            +
                #       <email>harry.potter@hogwarts.edu</email>
         
     | 
| 
      
 23 
     | 
    
         
            +
                #       <email>hpotter@JKRowling.com</email>
         
     | 
| 
      
 24 
     | 
    
         
            +
                #     </patron>
         
     | 
| 
      
 25 
     | 
    
         
            +
                class XmlDocument
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  attr_accessor :document
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  # Check if the embedded XML document is not present or invalid.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  def invalid?
         
     | 
| 
      
 31 
     | 
    
         
            +
                    @document.nil? or !document.is_a?(::Nokogiri::XML::Document) or @document.root.nil?
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # Check if the embedded XML document is present and valid
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def valid?
         
     | 
| 
      
 36 
     | 
    
         
            +
                    !invalid?
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # Create new XmlDocument instance.
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # The object will contain a new and emtpy Nokogiri XML Document.
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # The object will not be valid until a root node is added.
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # @param [String] encoding character encoding for the XML content; default value is 'utf-8'
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # @return [XmlDocument] new instance
         
     | 
| 
      
 44 
     | 
    
         
            +
                  def initialize(encoding = 'utf-8')
         
     | 
| 
      
 45 
     | 
    
         
            +
                    @document = Nokogiri::XML::Document.new
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @document.encoding = encoding
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  # Create a new instance initialized with the content of an XML file.
         
     | 
| 
      
 50 
     | 
    
         
            +
                  # @param [String] file path to the XML file
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # @return [XmlDocument] new instance
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def self.open(file)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    doc = XmlDocument.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                    doc.document = Nokogiri::XML(File.open(file))
         
     | 
| 
      
 55 
     | 
    
         
            +
                    doc
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  # Create a new instance initialized with an XML String.
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # @param [String] xml XML string
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # @return [XmlDocument] new instance
         
     | 
| 
      
 61 
     | 
    
         
            +
                  def self.parse(xml)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    doc = XmlDocument.new
         
     | 
| 
      
 63 
     | 
    
         
            +
                    doc.document = Nokogiri::XML.parse(xml)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    doc
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  # Create a new instance initialized with a Hash.
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # @note The Hash will be converted with Gyoku. See the Gyoku documentation for the Hash format requirements.
         
     | 
| 
      
 69 
     | 
    
         
            +
                  # @param [Hash] hash the content
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # @param [Hash] options options passed to Gyoku upon parsing the Hash into XML
         
     | 
| 
      
 71 
     | 
    
         
            +
                  # @return [XmlDocument] new instance
         
     | 
| 
      
 72 
     | 
    
         
            +
                  def self.from_hash(hash, options = {})
         
     | 
| 
      
 73 
     | 
    
         
            +
                    doc = XmlDocument.new
         
     | 
| 
      
 74 
     | 
    
         
            +
                    doc.document = Nokogiri::XML(Gyoku.xml(hash, options))
         
     | 
| 
      
 75 
     | 
    
         
            +
                    doc.document.encoding = 'utf-8'
         
     | 
| 
      
 76 
     | 
    
         
            +
                    doc
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  # Save the XML Document to a given XML file.
         
     | 
| 
      
 80 
     | 
    
         
            +
                  # @param [String] file name of the file to save to
         
     | 
| 
      
 81 
     | 
    
         
            +
                  # @param [Integer] indent amount of space for indenting; default 2
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # @param [String] encoding character encoding; default 'utf-8'
         
     | 
| 
      
 83 
     | 
    
         
            +
                  def save(file, indent = 2, encoding = 'utf-8')
         
     | 
| 
      
 84 
     | 
    
         
            +
                    fd = File.open(file, 'w')
         
     | 
| 
      
 85 
     | 
    
         
            +
                    @document.write_xml_to(fd, :indent => indent, :encoding => encoding)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    fd.close
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  # Export the XML Document to an XML string.
         
     | 
| 
      
 90 
     | 
    
         
            +
                  # @param [Hash] options options passed to the underlying Nokogiri::XML::Document#to_xml; default is:
         
     | 
| 
      
 91 
     | 
    
         
            +
                  #     !{indent: 2, encoding: 'utf-8'}
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # @return [String] a string
         
     | 
| 
      
 93 
     | 
    
         
            +
                  def to_xml(options = {})
         
     | 
| 
      
 94 
     | 
    
         
            +
                    options = {indent: 2, encoding: 'utf-8', save_with: Nokogiri::XML::Node::SaveOptions::DEFAULT_XML}.merge(options)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    @document.to_xml(options)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  # Export the XML Document to a Hash.
         
     | 
| 
      
 99 
     | 
    
         
            +
                  #
         
     | 
| 
      
 100 
     | 
    
         
            +
                  # @note The hash is generated using the Nori gem. The options passed to this call are used to configure Nori in
         
     | 
| 
      
 101 
     | 
    
         
            +
                  #       the constructor call. For content and syntax see the
         
     | 
| 
      
 102 
     | 
    
         
            +
                  #       {http://www.rubydoc.info/gems/nori/2.6.0 Nori documentation}. Nori also uses an enhanced
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #       String class with an extra method #attributes that will return a Hash containing tag-value pairs for each
         
     | 
| 
      
 104 
     | 
    
         
            +
                  #       attribute of the XML element.
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #
         
     | 
| 
      
 106 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 107 
     | 
    
         
            +
                  #
         
     | 
| 
      
 108 
     | 
    
         
            +
                  #     h = xml_doc.to_hash
         
     | 
| 
      
 109 
     | 
    
         
            +
                  #     # => { "patron" =>
         
     | 
| 
      
 110 
     | 
    
         
            +
                  #             { "name" => "Harry Potter",
         
     | 
| 
      
 111 
     | 
    
         
            +
                  #               "barcode" => "1234567890",
         
     | 
| 
      
 112 
     | 
    
         
            +
                  #               "access_level" => "student",
         
     | 
| 
      
 113 
     | 
    
         
            +
                  #               "email" => ["harry.potter@hogwarts.edu", "hpotter@JKRowling.com"],
         
     | 
| 
      
 114 
     | 
    
         
            +
                  #          }  }
         
     | 
| 
      
 115 
     | 
    
         
            +
                  #     h['patron']['barcode']
         
     | 
| 
      
 116 
     | 
    
         
            +
                  #     # => "12345678890"
         
     | 
| 
      
 117 
     | 
    
         
            +
                  #     h['patron']['barcode'].attributes
         
     | 
| 
      
 118 
     | 
    
         
            +
                  #     # => {"library" => "Hogwarts Library"}
         
     | 
| 
      
 119 
     | 
    
         
            +
                  #     h['patron']['barcode'].attributes['library']
         
     | 
| 
      
 120 
     | 
    
         
            +
                  #     # => "Hogwarts Library"
         
     | 
| 
      
 121 
     | 
    
         
            +
                  #
         
     | 
| 
      
 122 
     | 
    
         
            +
                  # @param [Hash] options
         
     | 
| 
      
 123 
     | 
    
         
            +
                  # @return [Hash]
         
     | 
| 
      
 124 
     | 
    
         
            +
                  def to_hash(options = {})
         
     | 
| 
      
 125 
     | 
    
         
            +
                    Nori.new(options).parse(to_xml)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                  # Check if the document validates against a given XML schema file.
         
     | 
| 
      
 129 
     | 
    
         
            +
                  # @param [String] schema the file path of the XML schema
         
     | 
| 
      
 130 
     | 
    
         
            +
                  # @return [Boolean]
         
     | 
| 
      
 131 
     | 
    
         
            +
                  def validates_against?(schema)
         
     | 
| 
      
 132 
     | 
    
         
            +
                    schema_doc = Nokogiri::XML::Schema.new(File.open(schema))
         
     | 
| 
      
 133 
     | 
    
         
            +
                    schema_doc.valid?(@document)
         
     | 
| 
      
 134 
     | 
    
         
            +
                  end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  # Check if the document validates against a given XML schema file.
         
     | 
| 
      
 137 
     | 
    
         
            +
                  # @return [Array<{Nokogiri::XML::SyntaxError}>] a list of validation errors
         
     | 
| 
      
 138 
     | 
    
         
            +
                  def validate(schema)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    schema_doc = Nokogiri::XML::Schema.new(File.open(schema))
         
     | 
| 
      
 140 
     | 
    
         
            +
                    schema_doc.validate(@document)
         
     | 
| 
      
 141 
     | 
    
         
            +
                  end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                  # Add a processing instruction to the current XML document.
         
     | 
| 
      
 144 
     | 
    
         
            +
                  # @note unlike regular nodes, these nodes are automatically added to the document.
         
     | 
| 
      
 145 
     | 
    
         
            +
                  # @param [String] name instruction name
         
     | 
| 
      
 146 
     | 
    
         
            +
                  # @param [String] content instruction content
         
     | 
| 
      
 147 
     | 
    
         
            +
                  # @return [Nokogiri::XML::Node] the processing instruction node
         
     | 
| 
      
 148 
     | 
    
         
            +
                  def add_processing_instruction(name, content)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    processing_instruction = Nokogiri::XML::ProcessingInstruction.new(@document, name, content)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    @document.root.add_previous_sibling processing_instruction
         
     | 
| 
      
 151 
     | 
    
         
            +
                    processing_instruction
         
     | 
| 
      
 152 
     | 
    
         
            +
                  end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                  # Get the root node of the XML Document.
         
     | 
| 
      
 155 
     | 
    
         
            +
                  #
         
     | 
| 
      
 156 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 157 
     | 
    
         
            +
                  #
         
     | 
| 
      
 158 
     | 
    
         
            +
                  #       puts xml_doc.root.to_xml
         
     | 
| 
      
 159 
     | 
    
         
            +
                  #       # =>
         
     | 
| 
      
 160 
     | 
    
         
            +
                  #           <patron>
         
     | 
| 
      
 161 
     | 
    
         
            +
                  #             ...
         
     | 
| 
      
 162 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 163 
     | 
    
         
            +
                  #
         
     | 
| 
      
 164 
     | 
    
         
            +
                  # @return [{Nokogiri::XML::Node}] the root node of the XML Document
         
     | 
| 
      
 165 
     | 
    
         
            +
                  def root
         
     | 
| 
      
 166 
     | 
    
         
            +
                    raise ArgumentError, 'XML document not valid.' if @document.nil?
         
     | 
| 
      
 167 
     | 
    
         
            +
                    @document.root
         
     | 
| 
      
 168 
     | 
    
         
            +
                  end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  # Set the root node of the XML Document.
         
     | 
| 
      
 171 
     | 
    
         
            +
                  #
         
     | 
| 
      
 172 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 173 
     | 
    
         
            +
                  #
         
     | 
| 
      
 174 
     | 
    
         
            +
                  #       patron = ::Nokogiri::XML::Node.new 'patron', xml_doc.document
         
     | 
| 
      
 175 
     | 
    
         
            +
                  #       xml_doc.root = patron
         
     | 
| 
      
 176 
     | 
    
         
            +
                  #       puts xml_doc.to_xml
         
     | 
| 
      
 177 
     | 
    
         
            +
                  #       # =>
         
     | 
| 
      
 178 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 179 
     | 
    
         
            +
                  #           <patron/>
         
     | 
| 
      
 180 
     | 
    
         
            +
                  #
         
     | 
| 
      
 181 
     | 
    
         
            +
                  # @param [{Nokogiri::XML::Node}] node new root node
         
     | 
| 
      
 182 
     | 
    
         
            +
                  # @return [{Nokogiri::XML::Node}] the new root node
         
     | 
| 
      
 183 
     | 
    
         
            +
                  def root=(node)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    raise ArgumentError, 'XML document not valid.' if @document.nil?
         
     | 
| 
      
 185 
     | 
    
         
            +
                    #noinspection RubyArgCount
         
     | 
| 
      
 186 
     | 
    
         
            +
                    @document.root = node
         
     | 
| 
      
 187 
     | 
    
         
            +
                  end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                  # Creates nodes using the Nokogiri build short syntax.
         
     | 
| 
      
 190 
     | 
    
         
            +
                  #
         
     | 
| 
      
 191 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 192 
     | 
    
         
            +
                  #
         
     | 
| 
      
 193 
     | 
    
         
            +
                  #     xml_doc.build(xml_doc.root) do |xml|
         
     | 
| 
      
 194 
     | 
    
         
            +
                  #       xml.books do
         
     | 
| 
      
 195 
     | 
    
         
            +
                  #         xml.book title: 'Quidditch Through the Ages', author: 'Kennilworthy Whisp', due_date: '1992-4-23'
         
     | 
| 
      
 196 
     | 
    
         
            +
                  #       end
         
     | 
| 
      
 197 
     | 
    
         
            +
                  #     end
         
     | 
| 
      
 198 
     | 
    
         
            +
                  #     p xml_doc.to_xml
         
     | 
| 
      
 199 
     | 
    
         
            +
                  #     # =>
         
     | 
| 
      
 200 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 201 
     | 
    
         
            +
                  #           <patron>
         
     | 
| 
      
 202 
     | 
    
         
            +
                  #               ...
         
     | 
| 
      
 203 
     | 
    
         
            +
                  #               <books>
         
     | 
| 
      
 204 
     | 
    
         
            +
                  #                 <book title="Quidditch Through the Ages" author="Kennilworthy Whisp" due_date="1992-4-23"/>
         
     | 
| 
      
 205 
     | 
    
         
            +
                  #               </books>
         
     | 
| 
      
 206 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 207 
     | 
    
         
            +
                  #
         
     | 
| 
      
 208 
     | 
    
         
            +
                  # @param [Nokogiri::XML::Node] at_node the node to attach the new nodes to;
         
     | 
| 
      
 209 
     | 
    
         
            +
                  #     optional - if missing or nil the new nodes will replace the entire document
         
     | 
| 
      
 210 
     | 
    
         
            +
                  # @param [Code block] block Build instructions
         
     | 
| 
      
 211 
     | 
    
         
            +
                  # @return [XmlDocument] the XML Document itself
         
     | 
| 
      
 212 
     | 
    
         
            +
                  def build(at_node = nil, options = {}, &block)
         
     | 
| 
      
 213 
     | 
    
         
            +
                    options = {encoding: 'utf-8' }.merge options
         
     | 
| 
      
 214 
     | 
    
         
            +
                    if at_node
         
     | 
| 
      
 215 
     | 
    
         
            +
                        Nokogiri::XML::Builder.new(options,at_node, &block)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    else
         
     | 
| 
      
 217 
     | 
    
         
            +
                      xml = Nokogiri::XML::Builder.new(options, &block)
         
     | 
| 
      
 218 
     | 
    
         
            +
                      @document = xml.doc
         
     | 
| 
      
 219 
     | 
    
         
            +
                    end
         
     | 
| 
      
 220 
     | 
    
         
            +
                    self
         
     | 
| 
      
 221 
     | 
    
         
            +
                  end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                  # Creates a new XML document with contents supplied in Nokogiri build short syntax.
         
     | 
| 
      
 224 
     | 
    
         
            +
                  #
         
     | 
| 
      
 225 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 226 
     | 
    
         
            +
                  #
         
     | 
| 
      
 227 
     | 
    
         
            +
                  #     xml_doc = ::Libis::Tools::XmlDocument.build do
         
     | 
| 
      
 228 
     | 
    
         
            +
                  #       patron {
         
     | 
| 
      
 229 
     | 
    
         
            +
                  #         name 'Harry Potter'
         
     | 
| 
      
 230 
     | 
    
         
            +
                  #         barcode( '1234567890', library: 'Hogwarts Library')
         
     | 
| 
      
 231 
     | 
    
         
            +
                  #         access_level 'student'
         
     | 
| 
      
 232 
     | 
    
         
            +
                  #         email 'harry.potter@hogwarts.edu'
         
     | 
| 
      
 233 
     | 
    
         
            +
                  #         email 'hpotter@JKRowling.com'
         
     | 
| 
      
 234 
     | 
    
         
            +
                  #         books {
         
     | 
| 
      
 235 
     | 
    
         
            +
                  #           book title: 'Quidditch Through the Ages', author: 'Kennilworthy Whisp', due_date: '1992-4-23'
         
     | 
| 
      
 236 
     | 
    
         
            +
                  #         }
         
     | 
| 
      
 237 
     | 
    
         
            +
                  #       }
         
     | 
| 
      
 238 
     | 
    
         
            +
                  #     end
         
     | 
| 
      
 239 
     | 
    
         
            +
                  #     p xml_doc.to_xml
         
     | 
| 
      
 240 
     | 
    
         
            +
                  #     # =>
         
     | 
| 
      
 241 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 242 
     | 
    
         
            +
                  #               <patron>
         
     | 
| 
      
 243 
     | 
    
         
            +
                  #           <name>Harry Potter</name>
         
     | 
| 
      
 244 
     | 
    
         
            +
                  #             <barcode library="Hogwarts Library">1234567890</barcode>
         
     | 
| 
      
 245 
     | 
    
         
            +
                  #           <access_level>student</access_level>
         
     | 
| 
      
 246 
     | 
    
         
            +
                  #             <email>harry.potter@hogwarts.edu</email>
         
     | 
| 
      
 247 
     | 
    
         
            +
                  #           <email>hpotter@JKRowling.com</email>
         
     | 
| 
      
 248 
     | 
    
         
            +
                  #             <books>
         
     | 
| 
      
 249 
     | 
    
         
            +
                  #               <book title="Quidditch Through the Ages" author="Kennilworthy Whisp" due_date="1992-4-23"/>
         
     | 
| 
      
 250 
     | 
    
         
            +
                  #           </books>
         
     | 
| 
      
 251 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 252 
     | 
    
         
            +
                  #
         
     | 
| 
      
 253 
     | 
    
         
            +
                  # @param [Code block] block Build instructions
         
     | 
| 
      
 254 
     | 
    
         
            +
                  # @return [XmlDocument] the new XML Document
         
     | 
| 
      
 255 
     | 
    
         
            +
                  def self.build(&block)
         
     | 
| 
      
 256 
     | 
    
         
            +
                    self.new.build(nil, &block)
         
     | 
| 
      
 257 
     | 
    
         
            +
                  end
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
                  # Adds a new XML node to the document.
         
     | 
| 
      
 260 
     | 
    
         
            +
                  #
         
     | 
| 
      
 261 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 262 
     | 
    
         
            +
                  #
         
     | 
| 
      
 263 
     | 
    
         
            +
                  #       xml_doc = ::Libis::Tools::XmlDocument.new
         
     | 
| 
      
 264 
     | 
    
         
            +
                  #       xml_doc.valid? # => false
         
     | 
| 
      
 265 
     | 
    
         
            +
                  #       xml_doc.add_node :patron
         
     | 
| 
      
 266 
     | 
    
         
            +
                  #       xml_doc.add_node :name, 'Harry Potter'
         
     | 
| 
      
 267 
     | 
    
         
            +
                  #       books = xml_doc.add_node :books, nil, nil, namespaces: { jkr: 'http://JKRowling.com', node_ns: 'jkr' }
         
     | 
| 
      
 268 
     | 
    
         
            +
                  #       xml_doc.add_node :book, nil, books,
         
     | 
| 
      
 269 
     | 
    
         
            +
                  #           title: 'Quidditch Through the Ages', author: 'Kennilworthy Whisp', due_date: '1992-4-23',
         
     | 
| 
      
 270 
     | 
    
         
            +
                  #           namespaces: { node_ns: 'jkr' }
         
     | 
| 
      
 271 
     | 
    
         
            +
                  #       p xml_doc.to_xml
         
     | 
| 
      
 272 
     | 
    
         
            +
                  #       # =>
         
     | 
| 
      
 273 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 274 
     | 
    
         
            +
                  #           <patron>
         
     | 
| 
      
 275 
     | 
    
         
            +
                  #               <name>Harry Potter</name>
         
     | 
| 
      
 276 
     | 
    
         
            +
                  #               <jkr:books xmlns:jkr="http://JKRowling.com">
         
     | 
| 
      
 277 
     | 
    
         
            +
                  #                 <jkr:book author="Kennilworthy Whisp" due_date="1992-4-23" title="Quidditch Through the Ages"/>
         
     | 
| 
      
 278 
     | 
    
         
            +
                  #               </jkr:books>
         
     | 
| 
      
 279 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 280 
     | 
    
         
            +
                  #
         
     | 
| 
      
 281 
     | 
    
         
            +
                  # @param [Array] args arguments being:
         
     | 
| 
      
 282 
     | 
    
         
            +
                  #     - tag for the new node
         
     | 
| 
      
 283 
     | 
    
         
            +
                  #     - optional content for new node; empty if nil or not present
         
     | 
| 
      
 284 
     | 
    
         
            +
                  #     - optional parent node for new node; root if nil or not present; xml document if root is not defined
         
     | 
| 
      
 285 
     | 
    
         
            +
                  #     - a Hash containing tag-value pairs for each attribute; the special key ':namespaces'
         
     | 
| 
      
 286 
     | 
    
         
            +
                  #       contains a Hash of namespace definitions as in {#add_namespaces}
         
     | 
| 
      
 287 
     | 
    
         
            +
                  # @return [Nokogiri::XML::Node] the new node
         
     | 
| 
      
 288 
     | 
    
         
            +
                  def add_node(*args)
         
     | 
| 
      
 289 
     | 
    
         
            +
                    attributes = {}
         
     | 
| 
      
 290 
     | 
    
         
            +
                    attributes = args.pop if args.last.is_a? Hash
         
     | 
| 
      
 291 
     | 
    
         
            +
                    name, value, parent = *args
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
                    return nil if name.nil?
         
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
      
 295 
     | 
    
         
            +
                    node = Nokogiri::XML::Node.new name.to_s, @document
         
     | 
| 
      
 296 
     | 
    
         
            +
                    node.content = value
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
                    if !parent.nil?
         
     | 
| 
      
 299 
     | 
    
         
            +
                      parent << node
         
     | 
| 
      
 300 
     | 
    
         
            +
                    elsif !self.root.nil?
         
     | 
| 
      
 301 
     | 
    
         
            +
                      self.root << node
         
     | 
| 
      
 302 
     | 
    
         
            +
                    else
         
     | 
| 
      
 303 
     | 
    
         
            +
                      self.root = node
         
     | 
| 
      
 304 
     | 
    
         
            +
                    end
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
                    return node if attributes.empty?
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
                    namespaces = attributes.delete :namespaces
         
     | 
| 
      
 309 
     | 
    
         
            +
                    add_namespaces(node, namespaces) if namespaces
         
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
                    add_attributes(node, attributes) if attributes
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
                    node
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
                  end
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                  # Add attributes to a node.
         
     | 
| 
      
 318 
     | 
    
         
            +
                  # @note The Nokogiri method Node#[]= is probably easier to use if you only want to add a single attribute ;the
         
     | 
| 
      
 319 
     | 
    
         
            +
                  #     main purpose of this method is to make it easier to add attributes in bulk or if you have them already
         
     | 
| 
      
 320 
     | 
    
         
            +
                  #     available as a Hash
         
     | 
| 
      
 321 
     | 
    
         
            +
                  #
         
     | 
| 
      
 322 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 323 
     | 
    
         
            +
                  #
         
     | 
| 
      
 324 
     | 
    
         
            +
                  #       xml_doc.add_attributes xml_doc.root, status: 'active', id: '123456'
         
     | 
| 
      
 325 
     | 
    
         
            +
                  #       xml_doc.to_xml
         
     | 
| 
      
 326 
     | 
    
         
            +
                  #       # =>
         
     | 
| 
      
 327 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 328 
     | 
    
         
            +
                  #           <patron id="123456" status="active">
         
     | 
| 
      
 329 
     | 
    
         
            +
                  #               ...
         
     | 
| 
      
 330 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 331 
     | 
    
         
            +
                  #
         
     | 
| 
      
 332 
     | 
    
         
            +
                  # @param [Nokogiri::XML::Node] node node to add the attributes to
         
     | 
| 
      
 333 
     | 
    
         
            +
                  # @param [Hash] attributes a Hash with tag - value pairs for each attribute
         
     | 
| 
      
 334 
     | 
    
         
            +
                  # @return [Nokogiri::XML::Node] the node
         
     | 
| 
      
 335 
     | 
    
         
            +
                  def add_attributes(node, attributes)
         
     | 
| 
      
 336 
     | 
    
         
            +
                    XmlDocument.add_attributes node, attributes
         
     | 
| 
      
 337 
     | 
    
         
            +
                  end
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
                  # (see #add_attributes)
         
     | 
| 
      
 340 
     | 
    
         
            +
                  def self.add_attributes(node, attributes)
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
                    attributes.each do |name, value|
         
     | 
| 
      
 343 
     | 
    
         
            +
                      node.set_attribute name.to_s, value
         
     | 
| 
      
 344 
     | 
    
         
            +
                    end
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
                    node
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
                  end
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
                  # Add namespace information to a node
         
     | 
| 
      
 351 
     | 
    
         
            +
                  #
         
     | 
| 
      
 352 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 353 
     | 
    
         
            +
                  #
         
     | 
| 
      
 354 
     | 
    
         
            +
                  #       xml_doc.add_namespaces xml_doc.root, jkr: 'http://JKRowling.com', node_ns: 'jkr'
         
     | 
| 
      
 355 
     | 
    
         
            +
                  #       xml_doc.to_xml
         
     | 
| 
      
 356 
     | 
    
         
            +
                  #       # =>
         
     | 
| 
      
 357 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 358 
     | 
    
         
            +
                  #           <jkr:patron xmlns:jkr="http://JKRowling.com">
         
     | 
| 
      
 359 
     | 
    
         
            +
                  #               ...
         
     | 
| 
      
 360 
     | 
    
         
            +
                  #           </jkr:patron>
         
     | 
| 
      
 361 
     | 
    
         
            +
                  #
         
     | 
| 
      
 362 
     | 
    
         
            +
                  #       xml_doc.add_namespaces xml_doc.root, nil => 'http://JKRowling.com'
         
     | 
| 
      
 363 
     | 
    
         
            +
                  #       xml_doc.to_xml
         
     | 
| 
      
 364 
     | 
    
         
            +
                  #       # =>
         
     | 
| 
      
 365 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 366 
     | 
    
         
            +
                  #           <patron xmlns="http://JKRowling.com">
         
     | 
| 
      
 367 
     | 
    
         
            +
                  #               ...
         
     | 
| 
      
 368 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 369 
     | 
    
         
            +
                  #
         
     | 
| 
      
 370 
     | 
    
         
            +
                  # @param [Nokogiri::XML::Node] node the node where the namespace info should be added to
         
     | 
| 
      
 371 
     | 
    
         
            +
                  # @param [Hash] namespaces a Hash with prefix - URI pairs for each namespace definition that should be added. The
         
     | 
| 
      
 372 
     | 
    
         
            +
                  #     special key +:node_ns+ is reserved for specifying the prefix for the node itself. To set the default
         
     | 
| 
      
 373 
     | 
    
         
            +
                  #     namespace, use the prefix +nil+
         
     | 
| 
      
 374 
     | 
    
         
            +
                  def add_namespaces(node, namespaces)
         
     | 
| 
      
 375 
     | 
    
         
            +
                    XmlDocument.add_namespaces node, namespaces
         
     | 
| 
      
 376 
     | 
    
         
            +
                  end
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
      
 378 
     | 
    
         
            +
                  # (see #add_namespaces)
         
     | 
| 
      
 379 
     | 
    
         
            +
                  def self.add_namespaces(node, namespaces)
         
     | 
| 
      
 380 
     | 
    
         
            +
             
     | 
| 
      
 381 
     | 
    
         
            +
                    node_ns = namespaces.delete :node_ns
         
     | 
| 
      
 382 
     | 
    
         
            +
                    default_ns = namespaces.delete nil
         
     | 
| 
      
 383 
     | 
    
         
            +
             
     | 
| 
      
 384 
     | 
    
         
            +
                    namespaces.each do |prefix, prefix_uri|
         
     | 
| 
      
 385 
     | 
    
         
            +
                      node.add_namespace prefix.to_s, prefix_uri
         
     | 
| 
      
 386 
     | 
    
         
            +
                    end
         
     | 
| 
      
 387 
     | 
    
         
            +
             
     | 
| 
      
 388 
     | 
    
         
            +
                    node.namespace_scopes.each do |ns|
         
     | 
| 
      
 389 
     | 
    
         
            +
                      node.namespace = ns if ns.prefix == node_ns.to_s
         
     | 
| 
      
 390 
     | 
    
         
            +
                    end if node_ns
         
     | 
| 
      
 391 
     | 
    
         
            +
             
     | 
| 
      
 392 
     | 
    
         
            +
                    node.default_namespace = default_ns if default_ns
         
     | 
| 
      
 393 
     | 
    
         
            +
             
     | 
| 
      
 394 
     | 
    
         
            +
                    node
         
     | 
| 
      
 395 
     | 
    
         
            +
             
     | 
| 
      
 396 
     | 
    
         
            +
                  end
         
     | 
| 
      
 397 
     | 
    
         
            +
             
     | 
| 
      
 398 
     | 
    
         
            +
                  # Search for nodes in the current document root.
         
     | 
| 
      
 399 
     | 
    
         
            +
                  #
         
     | 
| 
      
 400 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 401 
     | 
    
         
            +
                  #
         
     | 
| 
      
 402 
     | 
    
         
            +
                  #       nodes = xml_doc.xpath('//email')
         
     | 
| 
      
 403 
     | 
    
         
            +
                  #       nodes.size # => 2
         
     | 
| 
      
 404 
     | 
    
         
            +
                  #       nodes.map(&:content) # => ["harry.potter@hogwarts.edu", "hpotter@JKRowling.com"]
         
     | 
| 
      
 405 
     | 
    
         
            +
                  #
         
     | 
| 
      
 406 
     | 
    
         
            +
                  # @param [String] path XPath search string
         
     | 
| 
      
 407 
     | 
    
         
            +
                  # @return [{Nokogiri::XML::NodeSet}] set of nodes found
         
     | 
| 
      
 408 
     | 
    
         
            +
                  def xpath(path)
         
     | 
| 
      
 409 
     | 
    
         
            +
                    raise ArgumentError, 'XML document not valid.' if self.invalid?
         
     | 
| 
      
 410 
     | 
    
         
            +
                    @document.xpath(path.to_s)
         
     | 
| 
      
 411 
     | 
    
         
            +
                  end
         
     | 
| 
      
 412 
     | 
    
         
            +
             
     | 
| 
      
 413 
     | 
    
         
            +
                  # Check if the XML document contains certain element(s) anywhere in the XML document.
         
     | 
| 
      
 414 
     | 
    
         
            +
                  #
         
     | 
| 
      
 415 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 416 
     | 
    
         
            +
                  #
         
     | 
| 
      
 417 
     | 
    
         
            +
                  #       xml_doc.has_element? 'barcode[@library="Hogwarts Library"]' # => true
         
     | 
| 
      
 418 
     | 
    
         
            +
                  #
         
     | 
| 
      
 419 
     | 
    
         
            +
                  # @param [String] element_name name of the element(s) to search
         
     | 
| 
      
 420 
     | 
    
         
            +
                  # @return [Integer] number of elements found
         
     | 
| 
      
 421 
     | 
    
         
            +
                  def has_element?(element_name)
         
     | 
| 
      
 422 
     | 
    
         
            +
                    list = xpath("//#{element_name}")
         
     | 
| 
      
 423 
     | 
    
         
            +
                    list.nil? ? 0 : list.size
         
     | 
| 
      
 424 
     | 
    
         
            +
                  end
         
     | 
| 
      
 425 
     | 
    
         
            +
             
     | 
| 
      
 426 
     | 
    
         
            +
                  # Return the content of the first element found.
         
     | 
| 
      
 427 
     | 
    
         
            +
                  #
         
     | 
| 
      
 428 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 429 
     | 
    
         
            +
                  #
         
     | 
| 
      
 430 
     | 
    
         
            +
                  #       xml_doc.value('//email') # => "harry.potter@hogwarts.edu"
         
     | 
| 
      
 431 
     | 
    
         
            +
                  #
         
     | 
| 
      
 432 
     | 
    
         
            +
                  # @param [String] path the name or XPath term to search the node(s)
         
     | 
| 
      
 433 
     | 
    
         
            +
                  # @param [Node] parent parent node; document if nil
         
     | 
| 
      
 434 
     | 
    
         
            +
                  # @return [String] content or nil if not found
         
     | 
| 
      
 435 
     | 
    
         
            +
                  def value(path, parent = nil)
         
     | 
| 
      
 436 
     | 
    
         
            +
                    parent ||= document
         
     | 
| 
      
 437 
     | 
    
         
            +
                    parent.xpath(path).first.content rescue nil
         
     | 
| 
      
 438 
     | 
    
         
            +
                  end
         
     | 
| 
      
 439 
     | 
    
         
            +
             
     | 
| 
      
 440 
     | 
    
         
            +
                  # Return the content of the first element found.
         
     | 
| 
      
 441 
     | 
    
         
            +
                  #
         
     | 
| 
      
 442 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 443 
     | 
    
         
            +
                  #
         
     | 
| 
      
 444 
     | 
    
         
            +
                  #       xml_doc['email'] # => "harry.potter@hogwarts.edu"
         
     | 
| 
      
 445 
     | 
    
         
            +
                  #
         
     | 
| 
      
 446 
     | 
    
         
            +
                  # @param [String] path the name or XPath term to search the node(s)
         
     | 
| 
      
 447 
     | 
    
         
            +
                  # @return [String] content or nil if not found
         
     | 
| 
      
 448 
     | 
    
         
            +
                  def [](path)
         
     | 
| 
      
 449 
     | 
    
         
            +
                    xpath(path).first.content rescue nil
         
     | 
| 
      
 450 
     | 
    
         
            +
                  end
         
     | 
| 
      
 451 
     | 
    
         
            +
             
     | 
| 
      
 452 
     | 
    
         
            +
                  # Return the content of all elements found.
         
     | 
| 
      
 453 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 454 
     | 
    
         
            +
                  #
         
     | 
| 
      
 455 
     | 
    
         
            +
                  #       xml_doc.values('//email') # => [ "harry.potter@hogwarts.edu", "hpotter@JKRowling.com" ]
         
     | 
| 
      
 456 
     | 
    
         
            +
                  #
         
     | 
| 
      
 457 
     | 
    
         
            +
                  # @param (see #value)
         
     | 
| 
      
 458 
     | 
    
         
            +
                  # @return [Array<String>] content
         
     | 
| 
      
 459 
     | 
    
         
            +
                  def values(path)
         
     | 
| 
      
 460 
     | 
    
         
            +
                    xpath(path).map &:content
         
     | 
| 
      
 461 
     | 
    
         
            +
                  end
         
     | 
| 
      
 462 
     | 
    
         
            +
             
     | 
| 
      
 463 
     | 
    
         
            +
                  # Return the content of the first element in the set of nodes.
         
     | 
| 
      
 464 
     | 
    
         
            +
                  #
         
     | 
| 
      
 465 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 466 
     | 
    
         
            +
                  #
         
     | 
| 
      
 467 
     | 
    
         
            +
                  #       ::Libis::Tools::XmlDocument.get_content(xml_doc.xpath('//email')) # => "harry.potter@hogwarts.edu"
         
     | 
| 
      
 468 
     | 
    
         
            +
                  #
         
     | 
| 
      
 469 
     | 
    
         
            +
                  # @param [{Nokogiri::XML::NodeSet}] nodelist set of nodes to get content from
         
     | 
| 
      
 470 
     | 
    
         
            +
                  # @return [String] content of the first node; always returns at least an empty string
         
     | 
| 
      
 471 
     | 
    
         
            +
                  def self.get_content(nodelist)
         
     | 
| 
      
 472 
     | 
    
         
            +
                    (nodelist.first && nodelist.first.content) || ''
         
     | 
| 
      
 473 
     | 
    
         
            +
                  end
         
     | 
| 
      
 474 
     | 
    
         
            +
             
     | 
| 
      
 475 
     | 
    
         
            +
                  # Find a node and set its content.
         
     | 
| 
      
 476 
     | 
    
         
            +
                  #
         
     | 
| 
      
 477 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 478 
     | 
    
         
            +
                  #
         
     | 
| 
      
 479 
     | 
    
         
            +
                  #     xml_doc['//access_level'] = 'postgraduate'
         
     | 
| 
      
 480 
     | 
    
         
            +
                  #     p xml_doc.to_xml
         
     | 
| 
      
 481 
     | 
    
         
            +
                  #     # =>
         
     | 
| 
      
 482 
     | 
    
         
            +
                  #           <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
      
 483 
     | 
    
         
            +
                  #           <patron>
         
     | 
| 
      
 484 
     | 
    
         
            +
                  #             ...
         
     | 
| 
      
 485 
     | 
    
         
            +
                  #             <access_level>postgraduate</access_level>
         
     | 
| 
      
 486 
     | 
    
         
            +
                  #             ...
         
     | 
| 
      
 487 
     | 
    
         
            +
                  #           </patron>
         
     | 
| 
      
 488 
     | 
    
         
            +
                  #
         
     | 
| 
      
 489 
     | 
    
         
            +
                  # @param (see #value)
         
     | 
| 
      
 490 
     | 
    
         
            +
                  # @param [String] value the content
         
     | 
| 
      
 491 
     | 
    
         
            +
                  # @return [String] the value
         
     | 
| 
      
 492 
     | 
    
         
            +
                  def []=(path, value)
         
     | 
| 
      
 493 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 494 
     | 
    
         
            +
                      nodes = xpath(path)
         
     | 
| 
      
 495 
     | 
    
         
            +
                      nodes.first.content = value
         
     | 
| 
      
 496 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 497 
     | 
    
         
            +
                      # ignored
         
     | 
| 
      
 498 
     | 
    
         
            +
                    end
         
     | 
| 
      
 499 
     | 
    
         
            +
                  end
         
     | 
| 
      
 500 
     | 
    
         
            +
             
     | 
| 
      
 501 
     | 
    
         
            +
                  # Node access by method name.
         
     | 
| 
      
 502 
     | 
    
         
            +
                  #
         
     | 
| 
      
 503 
     | 
    
         
            +
                  # Nodes can be accessed through a method with signature the tag name of the node. There are several ways to use
         
     | 
| 
      
 504 
     | 
    
         
            +
                  # this shorthand method:
         
     | 
| 
      
 505 
     | 
    
         
            +
                  #
         
     | 
| 
      
 506 
     | 
    
         
            +
                  #  * without arguments it simply returns the first node found
         
     | 
| 
      
 507 
     | 
    
         
            +
                  #  * with one argument it retrieves the node's attribute
         
     | 
| 
      
 508 
     | 
    
         
            +
                  #  * with one argument and '=' sign it sets the content of the node
         
     | 
| 
      
 509 
     | 
    
         
            +
                  #  * with two arguments it sets the value of the node's attribute
         
     | 
| 
      
 510 
     | 
    
         
            +
                  #  * with a code block it implements the build pattern
         
     | 
| 
      
 511 
     | 
    
         
            +
                  #
         
     | 
| 
      
 512 
     | 
    
         
            +
                  #
         
     | 
| 
      
 513 
     | 
    
         
            +
                  #  Examples:
         
     | 
| 
      
 514 
     | 
    
         
            +
                  #
         
     | 
| 
      
 515 
     | 
    
         
            +
                  #       xml_doc.email
         
     | 
| 
      
 516 
     | 
    
         
            +
                  #       # => "harry.potter@hogwarts.edu"
         
     | 
| 
      
 517 
     | 
    
         
            +
                  #       p xml_doc.barcode 'library'
         
     | 
| 
      
 518 
     | 
    
         
            +
                  #       # => "Hogwarts Library"
         
     | 
| 
      
 519 
     | 
    
         
            +
                  #       xml_doc.access_level = 'postgraduate'
         
     | 
| 
      
 520 
     | 
    
         
            +
                  #       xml_doc.barcode 'library', 'Hogwarts Dumbledore Library'
         
     | 
| 
      
 521 
     | 
    
         
            +
                  #       xml_doc.dates do |dates|
         
     | 
| 
      
 522 
     | 
    
         
            +
                  #         dates.birth_date '1980-07-31'
         
     | 
| 
      
 523 
     | 
    
         
            +
                  #         dates.member_since '1991-09-01'
         
     | 
| 
      
 524 
     | 
    
         
            +
                  #       end
         
     | 
| 
      
 525 
     | 
    
         
            +
                  #       p xml_doc.to_xml
         
     | 
| 
      
 526 
     | 
    
         
            +
                  #       # =>  <patron>
         
     | 
| 
      
 527 
     | 
    
         
            +
                  #                 ...
         
     | 
| 
      
 528 
     | 
    
         
            +
                  #                 <barcode library='Hogwarts Dumbledore Library'>1234567890</barcode>
         
     | 
| 
      
 529 
     | 
    
         
            +
                  #                 <access_level>postgraduate</access_level>
         
     | 
| 
      
 530 
     | 
    
         
            +
                  #                 ...
         
     | 
| 
      
 531 
     | 
    
         
            +
                  #                 <dates>
         
     | 
| 
      
 532 
     | 
    
         
            +
                  #                   <birth_date>1980-07-31</birth_date>
         
     | 
| 
      
 533 
     | 
    
         
            +
                  #                   <member_since>1991-09-01</member_since>
         
     | 
| 
      
 534 
     | 
    
         
            +
                  #                 </dates>
         
     | 
| 
      
 535 
     | 
    
         
            +
                  #             </patron>
         
     | 
| 
      
 536 
     | 
    
         
            +
                  #
         
     | 
| 
      
 537 
     | 
    
         
            +
                  #
         
     | 
| 
      
 538 
     | 
    
         
            +
                  def method_missing(method, *args, &block)
         
     | 
| 
      
 539 
     | 
    
         
            +
                    super unless method.to_s =~ /^([a-z_][a-z_0-9]*)(!|=)?$/i
         
     | 
| 
      
 540 
     | 
    
         
            +
                    node = get_node($1)
         
     | 
| 
      
 541 
     | 
    
         
            +
                    node = add_node($1) if node.nil? || $2 == '!'
         
     | 
| 
      
 542 
     | 
    
         
            +
                    case args.size
         
     | 
| 
      
 543 
     | 
    
         
            +
                      when 0
         
     | 
| 
      
 544 
     | 
    
         
            +
                        if block_given?
         
     | 
| 
      
 545 
     | 
    
         
            +
                          build(node, &block)
         
     | 
| 
      
 546 
     | 
    
         
            +
                        end
         
     | 
| 
      
 547 
     | 
    
         
            +
                      when 1
         
     | 
| 
      
 548 
     | 
    
         
            +
                        if $2.blank?
         
     | 
| 
      
 549 
     | 
    
         
            +
                          return node[args.first.to_s]
         
     | 
| 
      
 550 
     | 
    
         
            +
                        else
         
     | 
| 
      
 551 
     | 
    
         
            +
                          node.content = args.first.to_s
         
     | 
| 
      
 552 
     | 
    
         
            +
                        end
         
     | 
| 
      
 553 
     | 
    
         
            +
                      when 2
         
     | 
| 
      
 554 
     | 
    
         
            +
                        node[args.first.to_s] = args[1].to_s
         
     | 
| 
      
 555 
     | 
    
         
            +
                        return node[args.first.to_s]
         
     | 
| 
      
 556 
     | 
    
         
            +
                      else
         
     | 
| 
      
 557 
     | 
    
         
            +
                        raise ArgumentError, 'Too many arguments.'
         
     | 
| 
      
 558 
     | 
    
         
            +
                    end
         
     | 
| 
      
 559 
     | 
    
         
            +
                    node
         
     | 
| 
      
 560 
     | 
    
         
            +
                  end
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
      
 562 
     | 
    
         
            +
                  # Get the first node matching the tag. The node will be seached with XPath search term = "//#!{tag}".
         
     | 
| 
      
 563 
     | 
    
         
            +
                  #
         
     | 
| 
      
 564 
     | 
    
         
            +
                  # @param [String] tag XML tag to look for; XPath syntax is allowed
         
     | 
| 
      
 565 
     | 
    
         
            +
                  # @param [Node] parent
         
     | 
| 
      
 566 
     | 
    
         
            +
                  def get_node(tag, parent = nil)
         
     | 
| 
      
 567 
     | 
    
         
            +
                    get_nodes(tag, parent).first
         
     | 
| 
      
 568 
     | 
    
         
            +
                  end
         
     | 
| 
      
 569 
     | 
    
         
            +
             
     | 
| 
      
 570 
     | 
    
         
            +
                  # Get all the nodes matching the tag. The node will be seached with XPath search term = "//#!{tag}".
         
     | 
| 
      
 571 
     | 
    
         
            +
                  #
         
     | 
| 
      
 572 
     | 
    
         
            +
                  # @param [String] tag XML tag to look for; XPath syntax is allowed
         
     | 
| 
      
 573 
     | 
    
         
            +
                  # @param [Node] parent
         
     | 
| 
      
 574 
     | 
    
         
            +
                  def get_nodes(tag, parent = nil)
         
     | 
| 
      
 575 
     | 
    
         
            +
                    parent ||= root
         
     | 
| 
      
 576 
     | 
    
         
            +
                    term = "#{tag.to_s =~ /^\// ? '' : '//'}#{tag.to_s}"
         
     | 
| 
      
 577 
     | 
    
         
            +
                    parent.xpath(term)
         
     | 
| 
      
 578 
     | 
    
         
            +
                  end
         
     | 
| 
      
 579 
     | 
    
         
            +
             
     | 
| 
      
 580 
     | 
    
         
            +
                end
         
     | 
| 
      
 581 
     | 
    
         
            +
             
     | 
| 
      
 582 
     | 
    
         
            +
              end
         
     | 
| 
      
 583 
     | 
    
         
            +
            end
         
     |