Module: JSON::LD::Frame
Instance Method Summary collapse
-
#cleanup_preserve(input) ⇒ Array, Hash
Replace @preserve keys with the values, also replace @null with null.
-
#frame(state, nodes, frame, parent, property) ⇒ Object
Frame input.
-
#remove_dependents(id, embeds) ⇒ Object
recursively remove dependent dangling embeds.
Methods included from Utils
#as_resource, #blank_node?, #index?, #list?, #node?, #node_reference?, #value?
Instance Method Details
#cleanup_preserve(input) ⇒ Array, Hash
Replace @preserve keys with the values, also replace @null with null
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 203 |
# File 'lib/json/ld/frame.rb', line 171 def cleanup_preserve(input) depth do #debug("cleanup preserve") {input.inspect} result = case input when Array # If, after replacement, an array contains only the value null remove the value, leaving an empty array. input.map {|o| cleanup_preserve(o)}.compact when Hash output = Hash.ordered input.each do |key, value| if key == '@preserve' # replace all key-value pairs where the key is @preserve with the value from the key-pair output = cleanup_preserve(value) else v = cleanup_preserve(value) # Because we may have added a null value to an array, we need to clean that up, if we possible v = v.first if v.is_a?(Array) && v.length == 1 && context.(key) != "@graph" && context.container(key).nil? output[key] = v end end output when '@null' # If the value from the key-pair is @null, replace the value with nul nil else input end #debug(" => ") {result.inspect} result end end |
#frame(state, nodes, frame, parent, property) ⇒ Object
Frame input. Input is expected in expanded form, but frame is in compacted form.
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 |
# File 'lib/json/ld/frame.rb', line 18 def frame(state, nodes, frame, parent, property) depth do debug("frame") {"state: #{state.inspect}"} debug("frame") {"nodes: #{nodes.keys.inspect}"} debug("frame") {"frame: #{frame.to_json(JSON_STATE)}"} debug("frame") {"parent: #{parent.to_json(JSON_STATE)}"} debug("frame") {"property: #{property.inspect}"} # Validate the frame validate_frame(state, frame) # Create a set of matched nodes by filtering nodes by checking the map of flattened nodes against frame # This gives us a hash of objects indexed by @id matches = filter_nodes(state, nodes, frame) debug("frame") {"matches: #{matches.keys.inspect}"} # Get values for embedOn and explicitOn = get_frame_flag(state, frame, 'embed'); explicit = get_frame_flag(state, frame, 'explicit'); debug("frame") {"embed: #{.inspect}, explicit: #{explicit.inspect}"} # For each id and node from the set of matched nodes ordered by id matches.keys.kw_sort.each do |id| element = matches[id] # If the active property is null, set the map of embeds in state to an empty map state = state.merge(:embeds => {}) if property.nil? output = {'@id' => id} # prepare embed meta info = {:parent => parent, :property => property} # If embedOn is true, and id is in map of embeds from state if && (existing = state[:embeds].fetch(id, nil)) # only overwrite an existing embed if it has already been added to its # parent -- otherwise its parent is somewhere up the tree from this # embed and the embed would occur twice once the tree is added = false = if existing[:parent].is_a?(Array) # If existing has a parent which is an array containing a JSON object with @id equal to id, element has already been embedded and can be overwritten, so set embedOn to true existing[:parent].detect {|p| p['@id'] == id} else # Otherwise, existing has a parent which is a node definition. Set embedOn to true if any of the items in parent property is a node definition or node reference for id because the embed can be overwritten existing[:parent].fetch(existing[:property], []).any? do |v| v.is_a?(Hash) && v.fetch('@id', nil) == id end end debug("frame") {"embed now: #{.inspect}"} # If embedOn is true, existing is already embedded but can be overwritten (state, id) if end unless # not embedding, add output without any other properties add_frame_output(state, parent, property, output) else # Add embed to map of embeds for id state[:embeds][id] = debug("frame") {"add embedded_node: #{.inspect}"} # Process each property and value in the matched node as follows element.keys.kw_sort.each do |prop| value = element[prop] if prop[0,1] == '@' # If property is a keyword, add property and a copy of value to output and continue with the next property from node output[prop] = value.dup next end # If property is not in frame: unless frame.has_key?(prop) debug("frame") {"non-framed property #{prop}"} # If explicitOn is false, Embed values from node in output using node as element and property as active property (state, element, prop, output) unless explicit # Continue to next property next end # Process each item from value as follows value.each do |item| debug("frame") {"value property #{prop.inspect} == #{item.inspect}"} # FIXME: If item is a JSON object with the key @list if list?(item) # create a JSON object named list with the key @list and the value of an empty array list = {'@list' => []} # Append list to property in output add_frame_output(state, output, prop, list) # Process each listitem in the @list array as follows item['@list'].each do |listitem| if node_reference?(listitem) itemid = listitem['@id'] debug("frame") {"list item of #{prop} recurse for #{itemid.inspect}"} # If listitem is a node reference process listitem recursively using this algorithm passing a new map of nodes that contains the @id of listitem as the key and the node reference as the value. Pass the first value from frame for property as frame, list as parent, and @list as active property. frame(state, {itemid => @node_map[itemid]}, frame[prop].first, list, '@list') else # Otherwise, append a copy of listitem to @list in list. debug("frame") {"list item of #{prop} non-node ref #{listitem.inspect}"} add_frame_output(state, list, '@list', listitem) end end elsif node_reference?(item) # If item is a node reference process item recursively # Recurse into sub-objects itemid = item['@id'] debug("frame") {"value property #{prop} recurse for #{itemid.inspect}"} # passing a new map as nodes that contains the @id of item as the key and the node reference as the value. Pass the first value from frame for property as frame, output as parent, and property as active property frame(state, {itemid => @node_map[itemid]}, frame[prop].first, output, prop) else # Otherwise, append a copy of item to active property in output. debug("frame") {"value property #{prop} non-node ref #{item.inspect}"} add_frame_output(state, output, prop, item) end end end # Process each property and value in frame in lexographical order, where property is not a keyword, as follows: frame.keys.kw_sort.each do |prop| next if prop[0,1] == '@' || output.has_key?(prop) property_frame = frame[prop] debug("frame") {"frame prop: #{prop.inspect}. property_frame: #{property_frame.inspect}"} # Set property frame to the first item in value or a newly created JSON object if value is empty. property_frame = property_frame.first || {} # Skip to the next property in frame if property is in output or if property frame contains @omitDefault which is true or if it does not contain @omitDefault but the value of omit default flag true. next if output.has_key?(prop) || get_frame_flag(state, property_frame, 'omitDefault') # Set the value of property in output to a new JSON object with a property @preserve and a value that is a copy of the value of @default in frame if it exists, or the string @null otherwise default = property_frame.fetch('@default', '@null').dup default = [default] unless default.is_a?(Array) output[prop] = [{"@preserve" => default.compact}] debug("=>") {"add default #{output[prop].inspect}"} end # Add output to parent add_frame_output(state, parent, property, output) end end end end |
#remove_dependents(id, embeds) ⇒ Object
recursively remove dependent dangling embeds
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/json/ld/frame.rb', line 294 def remove_dependents(id, ) debug("frame") {"remove dependents for #{id}"} depth do # get embed keys as a separate array to enable deleting keys in map .each do |id_dep, e| p = e.fetch(:parent, {}) if e.is_a?(Hash) next unless p.is_a?(Hash) pid = p.fetch('@id', nil) if pid == id debug("frame") {"remove #{id_dep} from embeds"} .delete(id_dep) remove_dependents(id_dep, ) end end end end |