using AIXM::Refinements module AIXM # Calculate OFMX-compliant payload hashes. # # @example with XML fragment string # xml = '' # AIXM::PayloadHash.new(xml).to_uuid # # @example with Nokogiri fragment # document = File.open("file.xml") { Nokogiri::XML(_1) } # AIXM::PayloadHash.new(document).to_uuid # # @see https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid class PayloadHash IGNORED_ATTRIBUTES = %w(mid source).freeze # @param fragment [Nokogiri::XML::DocumentFragment, Nokogiri::XML::Element, String] XML fragment def initialize(fragment) @fragment = case fragment when Nokogiri::XML::DocumentFragment then fragment when Nokogiri::XML::Element, String then Nokogiri::XML.fragment(fragment) else fail ArgumentError end end # @return [String] UUIDv3 def to_uuid uuid_for payload_array end private def payload_array @fragment.css('*').each_with_object([]) do |element, array| array << element.name.sub(/\A(\w+Uid)\w+/, '\1') # remove name extension element.attributes.sort.each do |name, attribute| array.push(name, attribute.value) unless IGNORED_ATTRIBUTES.include? name end array << element.child.text if element.children.one? && element.child.text? array << '' if element.children.none? end end def uuid_for(array) ::Digest::MD5.hexdigest(array.flatten.map(&:to_s).join('|')).unpack("a8a4a4a4a12").join("-") end # Insert OFMX-compliant payload hashes as mid attributes into an XML # document. # # Keep in mind: If you pass a Nokogiri::XML::Document, the mid attributes # are added into this document. In order to leave the original document # untouched, you have to `dup` it. # # @example with XML string # string = '' # converter = AIXM::PayloadHash::Mid.new(string) # converter.insert_mid.to_xml # returns XML as String # # @example with Nokogiri document # document = File.open("file.ofmx") { Nokogiri::XML(_1) } # converter = AIXM::PayloadHash::Mid.new(document) # converter.insert_mid.to_xml # returns XML as String # document.to_xml # returns XML as String as well # # @see https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid class Mid # @param document [Nokogiri::XML::Document, String] XML document def initialize(document) @document = case document when Nokogiri::XML::Document then document when String then Nokogiri::XML(document) else fail ArgumentError end end # Insert or update mid attributes on all *Uid elements # # @return [self] def insert_mid uid_elements.each do |element| element['mid'] = AIXM::PayloadHash.new(element).to_uuid end self end # Check mid attributes on all *Uid elements # # @return [Array] array of errors found def check_mid uid_elements.each_with_object([]) do |element, errors| unless element['mid'] == (uuid = AIXM::PayloadHash.new(element).to_uuid) errors << "#{element.line}: ERROR: Element '#{element.name}': mid should be #{uuid}" end end end # @return [String] XML document as XML string def to_xml @document.to_xml end private def uid_elements @document.xpath('//*[contains(local-name(), "Uid")]') end end end end