module DDEX::ERN

Constants

DEFAULT_CONFIG
ROOT_ELEMENT
VERSION_ATTR

Public Class Methods

read(xml, options = nil) click to toggle source

options ???

# File lib/ddex/ern.rb, line 145
def read(xml, options = nil)
  options ||= {}
  raise ArgumentError, "options must be a Hash" unless options.is_a?(Hash)

  doc   = parse(xml, options)
  ver   = options[:version] || find_version(doc)
  klass = load_version(ver)

  begin
    klass.from_xml(doc)
  rescue NoMethodError => e         # Yes, 4 real... this is from ROXML
    raise unless e.name == :root    # It's legit
    raise XMLLoadError, "XML is not well-formed"
  # This is a subclass of Exception(!) so we must name it
  rescue ROXML::RequiredElementMissing => e
    raise XMLLoadError, "missing required element: #{e}"
  end
end
supported_versions() click to toggle source
# File lib/ddex/ern.rb, line 135
def supported_versions
  config.values.map { |cfg| cfg[:version].dup }.sort
end
supports?(version) click to toggle source
# File lib/ddex/ern.rb, line 139
def supports?(version)
  version = version.to_s.downcase.strip
  config.any? { |name,cfg| name == version || cfg[:version] == version || cfg[:message_schema_version_id] == version }
end
write(object, options = nil) click to toggle source
# File lib/ddex/ern.rb, line 164
def write(object, options = nil)
  raise ArgumentError, "not a DDEX object" unless object.is_a?(DDEX::Element)

  options ||= {}
  raise ArgumentError, "options must be a Hash" unless options.is_a?(Hash)

  xmlopts = options.reject { |k, _| k == :schema }

  node = object.to_xml
  return node.to_xml(xmlopts) unless object.class.name.demodulize == ROOT_ELEMENT

  schema = schema_location(object, options[:schema])
  if schema
    node.add_namespace_definition(XML_SCHEMA_INSTANCE_PREFIX, XML_SCHEMA_INSTANCE_NS)
    node[XML_SCHEMA_INSTANCE_ATTR] = schema
  end

  doc = Nokogiri::XML::Document.new
  doc.root = node
  doc.to_xml(xmlopts)
end

Private Class Methods

find_version(doc) click to toggle source
# File lib/ddex/ern.rb, line 201
def find_version(doc)
  return doc.root[VERSION_ATTR] if doc.root[VERSION_ATTR]

  # Versions >= 4 don't have VERSION_ATTR so we resort to looking at namespaces.
  # For example, given: http://ddex.net/xml/ern/41
  # We'll try to match the end: "ern/41" or "ern/41/"
  names = doc.collect_namespaces.values
  version = config.values.find do |cfg|
    names.any? { |name| name =~ %r|#{ Regexp.quote(cfg[:message_schema_version_id]) }/?\z|i }
  end

  return unless version
  version[:message_schema_version_id]
end
load_version(version) click to toggle source
# File lib/ddex/ern.rb, line 231
def load_version(version)
  raise_unknown_version(version) if version.nil?

  # Some normalization
  v = version.strip.gsub(%r{//+}, "/").gsub(%r{\A/|/\Z}, "")
  klass, _ = config.find do |name, cfg|
    cfg[:message_schema_version_id] == v || cfg[:version] == v
  end
  raise_unknown_version(version) unless klass

  # >= 2.0 allows for one call
  DDEX::ERN.const_get(klass).const_get(ROOT_ELEMENT)
rescue LoadError, NameError => e
  raise_unknown_version(version)
end
parse(xml, options) click to toggle source
# File lib/ddex/ern.rb, line 216
def parse(xml, options)
  xml = File.read(xml) if xml.is_a?(String) and xml !~ /\A\s*<[?\w]/
  Nokogiri::XML(xml, nil, options[:encoding]) { |cfg| cfg.strict }
# ArgumentError means there was a problem with types, expected an int, got a str
rescue IOError, SystemCallError, ArgumentError => e
  raise XMLLoadError, "cannot load XML: #{e}"
rescue Nokogiri::XML::SyntaxError => e
  raise XMLLoadError, "XML parsing error: #{e}"
end
raise_unknown_version(version) click to toggle source
# File lib/ddex/ern.rb, line 226
def raise_unknown_version(version)
  message = "ERN version %s" % (version ? "'#{version}' is unsupported" : "attribute missing")
  raise UnknownVersionError, message
end
schema_location(object, schema) click to toggle source
# File lib/ddex/ern.rb, line 188
def schema_location(object, schema)
  # extract version from namespace e.g., DDEX::ERN::V36::NewReleaseMessage
  ver = object.class.name.split("::")[-2]
  return unless schema or config.include?(ver)

  # Check if it's "NS schema"
  if schema && schema.strip.include?(" ")
    schema
  else
    sprintf "%s %s", object.class.ns[1], schema || config[ver][:schema]
  end
end