Module: JSON::LD::Compact
Instance Method Summary collapse
-
#compact(element, property = nil) ⇒ Array, Hash
Compact an expanded Array or Hash given an active property and a context.
Methods included from Utils
#blank_node?, #index?, #list?, #node?, #node_reference?, #value?
Instance Method Details
#compact(element, property = nil) ⇒ Array, Hash
Compact an expanded Array or Hash given an active property and a context.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/json/ld/compact.rb', line 11 def compact(element, property = nil) if property.nil? debug("compact") {"element: #{element.inspect}, ec: #{context.inspect}"} else debug("compact") {"property: #{property.inspect}"} end case element when Array # 1) If value is an array, process each item in value recursively using # this algorithm, passing copies of the active context and the # active property. debug("compact") {"Array #{element.inspect}"} result = depth {element.map {|v| compact(v, property)}} # If element has a single member and the active property has no # @container mapping to @list or @set, the compacted value is that # member; otherwise the compacted value is element if result.length == 1 && @options[:compactArrays] debug("=> extract single element: #{result.first.inspect}") result.first else debug("=> array result: #{result.inspect}") result end when Hash # 2) Otherwise, if element is an object: result = {} if k = %w(@list @set @value).detect {|container| element.has_key?(container)} debug("compact") {"#{k}: container(#{property}) = #{context.container(property)}"} end k ||= '@id' if element.keys == ['@id'] case k when '@value', '@id' # If element has an @value property or element is a node reference, return the result of performing Value Compaction on element using active property. v = context.compact_value(property, element, :depth => @depth) debug("compact") {"value optimization for #{property}, return as #{v.inspect}"} return v when '@list' # Otherwise, if the active property has a @container mapping to @list and element has a corresponding @list property, recursively compact that property's value passing a copy of the active context and the active property ensuring that the result is an array with all null values removed. # If there already exists a value for active property in element and the full IRI of property is also coerced to @list, return an error. # FIXME: check for full-iri list coercion # Otherwise store the resulting array as value of active property if empty or property otherwise. compacted_key = context.compact_iri('@list', :position => :predicate, :depth => @depth) v = depth { compact(element[k], property) } # Return either the result as an array, as an object with a key of @list (or appropriate alias from active context v = [v].compact unless v.is_a?(Array) unless context.container(property) == '@list' v = {compacted_key => v} if element['@index'] compacted_key = context.compact_iri('@index', :position => :predicate, :depth => @depth) v[compacted_key] = element['@index'] end end debug("compact") {"@list result, return as #{v.inspect}"} return v end # Check for property generators before continuing with other elements # For each term pg in the active context which is a property generator # Select property generator terms by shortest term context.mappings.keys.sort.each do |term| next unless context.mapping(term).is_a?(Array) # Using the first expanded IRI p associated with the property generator = context.mapping(term).map(&:to_s) p = .first.to_s # Skip to the next property generator term unless p is a property of element next unless element.has_key?(p) debug("compact") {"check pg #{term}: #{}"} # For each node n which is a value of p in element node_values = [] element[p].dup.each do |n| # For each expanded IRI pi associated with the property generator other than p next unless [1..-1].all? do |pi| debug("compact") {"check #{pi} for (#{n.inspect})"} element.has_key?(pi) && element[pi].any? do |ni| nodesEquivalent?(n, ni) end end # Remove n as a value of all p and pi in element debug("compact") {"removed matched value #{n.inspect} from #{.inspect}"} .each do |pi| # FIXME: This removes all values equivalent to n, not just the first element[pi] = element[pi].reject {|ni| nodesEquivalent?(n, ni)} end # Add the result of performing the compaction algorithm on n to pg to output node_values << n end # If there are node_values, or all the values from expanded_iris are empty, add node_values to result, and remove the expanded_iris as keys from element if node_values.length > 0 || .all? {|pi| element.has_key?(pi) && element[pi].empty?} debug("compact") {"compact extracted pg values"} result[term] = depth { compact(node_values, term)} result[term] = [result[term]] if !result[term].is_a?(Array) && context.container(term) == '@set' debug("compact") {"remove empty pg keys from element"} .each do |pi| debug(" =>") {"#{pi}? #{element.fetch(pi, []).empty?}"} element.delete(pi) if element.fetch(pi, []).empty? end end end # Otherwise, for each property and value in element: element.each do |key, value| debug("compact") {"#{key}: #{value.inspect}"} if %(@id @type).include?(key) position = key == '@id' ? :subject : :type compacted_key = context.compact_iri(key, :position => :predicate, :depth => @depth) result[compacted_key] = case value when String # If value is a string, the compacted value is the result of performing IRI Compaction on value. debug {" => compacted string for #{key}"} context.compact_iri(value, :position => position, :depth => @depth) when Array # Otherwise, value must be an array. Perform IRI Compaction on every entry of value. If value contains just one entry, value is set to that entry compacted_value = value.map {|v2| context.compact_iri(v2, :position => position, :depth => @depth)} debug {" => compacted value(#{key}): #{compacted_value.inspect}"} compacted_value = compacted_value.first if compacted_value.length == 1 && @options[:compactArrays] compacted_value end elsif key == '@index' && context.container(property) == '@index' # Skip the annotation key if annotations being applied next else if value.empty? # Make sure that an empty array is preserved compacted_key = context.compact_iri(key, :position => :predicate, :depth => @depth) next if compacted_key.nil? result[compacted_key] = value next end # For each item in value: value = [value] if key == '@index' && value.is_a?(String) raise ProcessingError, "found #{value.inspect} for #{key} of #{element.inspect}" unless value.is_a?(Array) value.each do |item| compacted_key = context.compact_iri(key, :position => :predicate, :value => item, :depth => @depth) # Result for this item, typically the output object itself item_result = result item_key = compacted_key debug {" => compacted key: #{compacted_key.inspect} for #{item.inspect}"} next if compacted_key.nil? # Language maps and annotations if field = %w(@language @index).detect {|kk| context.container(compacted_key) == kk} item_result = result[compacted_key] ||= Hash.new item_key = item[field] end compacted_item = depth {self.compact(item, compacted_key)} debug {" => compacted value: #{compacted_value.inspect}"} case item_result[item_key] when Array item_result[item_key] << compacted_item when nil if !compacted_value.is_a?(Array) && context.container(compacted_key) == '@set' compacted_item = [compacted_item].compact debug {" => as @set: #{compacted_item.inspect}"} end item_result[item_key] = compacted_item else item_result[item_key] = [item_result[item_key], compacted_item] end end end end # Re-order result keys r = Hash.ordered result.keys.kw_sort.each {|kk| r[kk] = result[kk]} r else # For other types, the compacted value is the element value debug("compact") {element.class.to_s} element end end |