def to_ordered_hash(opts={})
      force = opts.fetch(:force, false)
      sort_json_ld_keys = opts.fetch(:sort_json_ld_keys, true)

      unless force
        self.validate
      end

      export_hash = IIIF::OrderedHash.new

      if sort_json_ld_keys
        self.keys.select { |k| k.start_with?('@') }.sort!.each do |k|
          export_hash[k] = self.data[k]
        end
      end

      sub_opts = {
        include_context: false,
        sort_json_ld_keys: sort_json_ld_keys,
        force: force
      }
      self.keys.each do |k|
        unless sort_json_ld_keys && k.start_with?('@')
          if self.data[k].respond_to?(:to_ordered_hash) #.respond_to?(:to_ordered_hash)
            export_hash[k] = self.data[k].to_ordered_hash(sub_opts)

          elsif self.data[k].kind_of?(Hash)
            export_hash[k] = IIIF::OrderedHash.new
            self.data[k].each do |sub_k, v|

              if v.respond_to?(:to_ordered_hash)
                export_hash[k][sub_k] = v.to_ordered_hash(sub_opts)

              elsif v.kind_of?(Array)
                export_hash[k][sub_k] = []
                v.each do |member|
                  if member.respond_to?(:to_ordered_hash)
                    export_hash[k][sub_k] << member.to_ordered_hash(sub_opts)
                  else
                    export_hash[k][sub_k] << member
                  end
                end
              else
                export_hash[k][sub_k] = v
              end
            end

          elsif self.data[k].kind_of?(Array)
            export_hash[k] = []

            self.data[k].each do |member|
              if member.respond_to?(:to_ordered_hash)
                export_hash[k] << member.to_ordered_hash(sub_opts)

              elsif member.kind_of?(Hash)
                hsh = IIIF::OrderedHash.new
                export_hash[k] << hsh
                member.each do |sub_k,v|

                  if v.respond_to?(:to_ordered_hash)
                    hsh[sub_k] = v.to_ordered_hash(sub_opts)

                  elsif v.kind_of?(Array)
                    hsh[sub_k] = []

                    v.each do |sub_member|
                      if sub_member.respond_to?(:to_ordered_hash)
                        hsh[sub_k] << sub_member.to_ordered_hash(sub_opts)
                      else
                        hsh[sub_k] << sub_member
                      end
                    end
                  else
                    hsh[sub_k] = v
                  end
                end

              else
                export_hash[k] << member
                # there are no nested arrays, right?
              end
            end
          else
            export_hash[k] = self.data[k]
          end

        end
      end
      export_hash.remove_empties
      export_hash.camelize_keys
      export_hash
    end
def to_ordered_hash(opts={})
      force = opts.fetch(:force, false)
      sort_json_ld_keys = opts.fetch(:sort_json_ld_keys, true)

      unless force
        self.validate
      end

      export_hash = IIIF::OrderedHash.new

      if sort_json_ld_keys
        self.keys.select { |k| k.start_with?('@') }.sort!.each do |k|
          export_hash[k] = self.data[k]
        end
      end

      sub_opts = {
        include_context: false,
        sort_json_ld_keys: sort_json_ld_keys,
        force: force
      }
      self.keys.each do |k|
        unless sort_json_ld_keys && k.start_with?('@')
          if self.data[k].respond_to?(:to_ordered_hash) #.respond_to?(:to_ordered_hash)
            export_hash[k] = self.data[k].to_ordered_hash(sub_opts)

          elsif self.data[k].kind_of?(Hash)
            export_hash[k] = IIIF::OrderedHash.new
            self.data[k].each do |sub_k, v|

              if v.respond_to?(:to_ordered_hash)
                export_hash[k][sub_k] = v.to_ordered_hash(sub_opts)

              elsif v.kind_of?(Array)
                export_hash[k][sub_k] = []
                v.each do |member|
                  if member.respond_to?(:to_ordered_hash)
                    export_hash[k][sub_k] << member.to_ordered_hash(sub_opts)
                  else
                    export_hash[k][sub_k] << member
                  end
                end
              else
                export_hash[k][sub_k] = v
              end
            end

          elsif self.data[k].kind_of?(Array)
            export_hash[k] = []

            self.data[k].each do |member|
              if member.respond_to?(:to_ordered_hash)
                export_hash[k] << member.to_ordered_hash(sub_opts)

              elsif member.kind_of?(Hash)
                hsh = IIIF::OrderedHash.new
                export_hash[k] << hsh
                member.each do |sub_k,v|

                  if v.respond_to?(:to_ordered_hash)
                    hsh[sub_k] = v.to_ordered_hash(sub_opts)

                  elsif v.kind_of?(Array)
                    hsh[sub_k] = []

                    v.each do |sub_member|
                      if sub_member.respond_to?(:to_ordered_hash)
                        hsh[sub_k] << sub_member.to_ordered_hash(sub_opts)
                      else
                        hsh[sub_k] << sub_member
                      end
                    end
                  else
                    hsh[sub_k] = v
                  end
                end

              else
                export_hash[k] << member
                # there are no nested arrays, right?
              end
            end
          else
            export_hash[k] = self.data[k]
          end

        end
      end
      export_hash.remove_empties
      export_hash.camelize_keys
      export_hash
    end
Options:
  * force: (true|false). Skips validations.
  * sort_json_ld_keys: (true|false). Brings all properties starting with
      '@'. Default: true. to the top of the document and sorts them.