Module: OM::XML::TermValueOperators
- Defined in:
- lib/om/xml/term_value_operators.rb
Instance Method Summary collapse
-
#assign_nested_attributes_for_collection_association(pointer, new_values) ⇒ Object
Will update the name of the Person with ID 1, build a new associated person with the name ‘John’, and mark the associated Person with ID 2 for destruction.
-
#build_ancestors(parent_select, parent_index) ⇒ Nokogiri::XML::Node, Array
Creates necesary ancestor nodes to support inserting a new term value where the ancestor node(s) don’t exist yet.
- #delete_on_update?(node, new_value) ⇒ Boolean
-
#insert_from_template(parent_node, new_values, template) ⇒ Nokogiri::XML::Node
Insert xml containing
new_values
intoparent_node
. -
#property_values(*lookup_args) ⇒ Object
alias for term_values.
-
#term_value_delete(opts = {}) ⇒ Object
def term_value_set(term_ref, query_opts, node_index, new_value) end.
- #term_value_update(node_select, node_index, new_value, opts = {}) ⇒ Object
-
#term_values(*term_pointer) ⇒ Object
Retrieves all of the nodes from the current document that match
term_pointer
and returns an array of their values. - #term_values_append(opts = {}) ⇒ Object
- #update_values(params = {}) ⇒ Object
Instance Method Details
#assign_nested_attributes_for_collection_association(pointer, new_values) ⇒ Object
Will update the name of the Person with ID 1, build a new associated person with the name ‘John’, and mark the associated Person with ID 2 for destruction.
Also accepts an Array of attribute hashes:
assign_nested_attributes_for_collection_association(:people, [
{ name: 'Peter' },
{ name: 'John', role: 'Creator' },
{ name: 'Bess' }
])
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 |
# File 'lib/om/xml/term_value_operators.rb', line 72 def assign_nested_attributes_for_collection_association(pointer, new_values) term = self.class.terminology.retrieve_term( *OM.pointers_to_flat_array(pointer,false) ) xpath = self.class.terminology.xpath_with_indexes(*pointer) current_values = term_values(*pointer) new_values = term.sanitize_new_values(new_values) if current_values.length > new_values.length starting_index = new_values.length + 1 starting_index.upto(current_values.size).each do |index| term_value_delete select: xpath, child_index: index end end # Populate the response hash appropriately, using hierarchical names for terms as keys rather than the given pointers. result = new_values.dup # Fill out the pointer completely if the final term is a NamedTermProxy if term.kind_of? OM::XML::NamedTermProxy pointer.pop pointer = pointer.concat(term.proxy_pointer) end parent_pointer = pointer.dup parent_pointer.pop parent_xpath = self.class.terminology.xpath_with_indexes(*parent_pointer) template_pointer = OM.pointers_to_flat_array(pointer,false) # If the value doesn't exist yet, append it. Otherwise, update the existing value. new_values.each_with_index do |z, y| if find_by_terms(*pointer)[y.to_i].nil? result.delete(y) term_values_append(:parent_select=>parent_pointer,:parent_index=>0,:template=>template_pointer,:values=>z) new_array_index = find_by_terms(*pointer).length - 1 result[new_array_index] = z else term_value_update(xpath, y.to_i, z) end end return result end |
#build_ancestors(parent_select, parent_index) ⇒ Nokogiri::XML::Node, Array
Creates necesary ancestor nodes to support inserting a new term value where the ancestor node(s) don’t exist yet. Corrects node indexes in the pointer array to correspond to the ancestors that it creates. Returns a two-value array with the ‘parent’ node and a corrected pointer array
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/om/xml/term_value_operators.rb', line 181 def build_ancestors(parent_select, parent_index) parent_select = Array(parent_select) parent_nodeset = find_by_terms(*parent_select) starting_point = node_from_set(parent_nodeset, parent_index) if starting_point.nil? starting_point = [] end to_build = [] until !starting_point.empty? to_build = [parent_select.pop] + to_build starting_point = find_by_terms(*parent_select) if starting_point.empty? && parent_select.empty? raise OM::XML::TemplateMissingException, "Cannot insert nodes into the document because it is empty. Try defining self.xml_template on the #{self.class} class." end end to_build.each do |term_pointer| parent_select << term_pointer # If pointers in parent_select don't match with the indexes of built ancestors, correct the hash if find_by_terms(*parent_select+[{}]).length == 0 if parent_select.last.kind_of?(Hash) suspect_pointer = parent_select.pop term_key = suspect_pointer.keys.first if parent_select.empty? corrected_term_index = find_by_terms(term_key).length else corrected_term_index = find_by_terms(*parent_select+[{}]).length end parent_select << {term_key => corrected_term_index} end end template_pointer = OM.pointers_to_flat_array(parent_select,false) new_values = [""] insert_from_template(starting_point.first, new_values, template_pointer) starting_point = find_by_terms(*parent_select+[{}]) # If pointers in parent_select don't match with the indexes of built ancestors, correct the hash if starting_point.empty? raise ::StandardError, "Oops. Something went wrong adding #{term_pointer.inspect} to #{parent_select.inspect} while building ancestors. Expected to find something at #{self.class.terminology.xpath_for(*parent_select)}. The current xml is\n #{self.to_xml}" end end if parent_index > starting_point.length parent_index = starting_point.length - 1 end return node_from_set(starting_point, parent_index) end |
#delete_on_update?(node, new_value) ⇒ Boolean
238 239 240 |
# File 'lib/om/xml/term_value_operators.rb', line 238 def delete_on_update?(node, new_value) new_value.nil? || new_value == :delete end |
#insert_from_template(parent_node, new_values, template) ⇒ Nokogiri::XML::Node
Insert xml containing new_values
into parent_node
. Generate the xml based on template
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 |
# File 'lib/om/xml/term_value_operators.rb', line 146 def insert_from_template(parent_node, new_values, template) ng_xml_will_change! # If template is a string, use it as the template, otherwise use it as arguments to xml_builder_template unless template.instance_of?(String) template_args = Array(template) if template_args.last.kind_of?(Hash) template_opts = template_args.delete_at(template_args.length - 1) template_args << template_opts end template_args = OM.pointers_to_flat_array(template_args,false) template = self.class.terminology.xml_builder_template( *template_args ) end #if there is an xpath element pointing to text() need to change to just 'text' so it references the text method for the parent node template.gsub!(/text\(\)/, 'text') builder = Nokogiri::XML::Builder.with(parent_node) do |xml| new_values.each do |builder_new_value| builder_new_value = builder_new_value.gsub(/'/, "\\\\'") # escape any apostrophes in the new value if matchdata = /xml\.@(\w+)/.match(template) parent_node.set_attribute(matchdata[1], builder_new_value) else builder_arg = eval('"'+ template + '"') # this inserts builder_new_value into the builder template eval(builder_arg) end end end return parent_node end |
#property_values(*lookup_args) ⇒ Object
alias for term_values
24 25 26 |
# File 'lib/om/xml/term_value_operators.rb', line 24 def property_values(*lookup_args) term_values(*lookup_args) end |
#term_value_delete(opts = {}) ⇒ Object
def term_value_set(term_ref, query_opts, node_index, new_value) end
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/om/xml/term_value_operators.rb', line 245 def term_value_delete(opts={}) ng_xml_will_change! parent_select = Array( opts[:parent_select] ) parent_index = opts[:parent_index] child_index = opts[:child_index] xpath_select = opts[:select] if !xpath_select.nil? node = find_by_terms_and_value(xpath_select).first else # parent_nodeset = find_by_terms_and_value(parent_select, parent_select) parent_nodeset = find_by_terms_and_value(*parent_select) if parent_index.nil? node = node_from_set(parent_nodeset, child_index) else parent = node_from_set(parent_nodeset, parent_index) # this next line is a hack around the fact that element_children() sometimes doesn't work. node = node_from_set(parent.xpath("*"), child_index) end end node.remove end |
#term_value_update(node_select, node_index, new_value, opts = {}) ⇒ Object
227 228 229 230 231 232 233 234 235 236 |
# File 'lib/om/xml/term_value_operators.rb', line 227 def term_value_update(node_select,node_index,new_value,opts={}) ng_xml_will_change! node = find_by_terms_and_value(*node_select)[node_index] if delete_on_update?(node, new_value) node.remove else node.content = new_value end end |
#term_values(*term_pointer) ⇒ Object
Retrieves all of the nodes from the current document that match term_pointer
and returns an array of their values
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/om/xml/term_value_operators.rb', line 7 def term_values(*term_pointer) result = [] xpath = self.class.terminology.xpath_with_indexes(*term_pointer) #if value is on line by itself sometimes does not trim leading and trailing whitespace for a text node so will detect and fix it trim_text = !xpath.nil? && !xpath.index("text()").nil? find_by_terms(*term_pointer).each {|node| result << (trim_text ? node.text.strip : node.text) } if term_pointer.length == 1 && term_pointer.first.kind_of?(String) OM.logger.warn "Passing a xpath to term_values means that OM can not properly find the associated term. Pass a term pointer instead." if OM.logger result else term = self.class.terminology.retrieve_term(*OM.pointers_to_flat_array(OM.destringify(term_pointer), false)) term.deserialize(result) end end |
#term_values_append(opts = {}) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/om/xml/term_value_operators.rb', line 118 def term_values_append(opts={}) parent_select = Array( opts[:parent_select] ) parent_index = opts[:parent_index] template = opts[:template] new_values = Array( opts[:values] ) parent_nodeset = find_by_terms(*parent_select) parent_node = node_from_set(parent_nodeset, parent_index) if parent_node.nil? if parent_select.empty? parent_node = ng_xml.root else parent_node = build_ancestors(parent_select, parent_index) end end insert_from_template(parent_node, new_values, template) return parent_node end |
#update_values(params = {}) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/om/xml/term_value_operators.rb', line 32 def update_values(params={}) # remove any terms from params that this datastream doesn't recognize params.delete_if do |term_pointer,new_values| if term_pointer.kind_of?(String) true else !self.class.terminology.has_term?(*OM.destringify(term_pointer)) end end params.inject({}) do |result, (term_pointer,new_values)| pointer = OM.destringify(term_pointer) hn = OM::XML::Terminology.term_hierarchical_name(*pointer) result[hn] = assign_nested_attributes_for_collection_association(pointer, new_values) result end end |