Class: OM::XML::Term

Inherits:
Object
  • Object
show all
Includes:
TreeNode, TermBuilder
Defined in:
lib/om/xml/term.rb

Overview

Special options: type, index_as, attributes, is_root_term, required

Instance Attribute Summary collapse

Attributes included from TreeNode

#ancestors

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TreeNode

#add_child, #parent, #retrieve_child, #set_parent

Constructor Details

#initialize(name, opts = {}, terminology = nil) ⇒ Term

h2. Namespaces By default, OM assumes you have no namespace defined unless it is explicitly defined at the root of your document.

Parameters:

  • name (Symbol)

    the name to refer to this term by

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :index_as (Array)

    a list of indexing hints provided to to_solr

  • :path (String)

    partial xpath that points to the node.

  • :attributes (Hash)

    xml attributes to match in the selector

  • :namespace_prefix (String)

    xml namespace for this node. If not provided, the default namespace set in the terminology will be used.

  • :type (Symbol)

    one of :string, :date, :time :integer. Defaults to :string



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/om/xml/term.rb', line 55

def initialize(name, opts={}, terminology=nil)
  opts = {:ancestors=>[], :children=>{}}.merge(opts)
  [:children, :ancestors,:path, :index_as, :required, :variant_of, :path, :attributes, :default_content_path, :namespace_prefix].each do |accessor_name|
    instance_variable_set("@#{accessor_name}", opts.fetch(accessor_name, nil) )
  end

  self.type = opts[:type] || :string

  unless terminology.nil?
    if opts[:namespace_prefix].nil?
      unless terminology.namespaces["xmlns"].nil?
        @namespace_prefix = "oxns"
      end
    end
  end
  @name = name
  if @path.nil? || @path.empty?
    @path = name.to_s
  end
end

Instance Attribute Details

#attributesObject

Any XML attributes that qualify the Term.

Examples:

Declare a Term that has a given attribute (ie. //title)

t.english_title(:path=>"title", :attributes=>{"xml:lang"=>"eng"}

Use nil to point to nodes that do not have a given attribute (ie. //title)

t.title_without_lang_attribute(:path=>"title", :attributes=>{"xml:lang"=>nil})


21
22
23
# File 'lib/om/xml/term.rb', line 21

def attributes
  @attributes
end

#childrenObject

Returns the value of attribute children.



13
14
15
# File 'lib/om/xml/term.rb', line 13

def children
  @children
end

#default_content_pathObject

Returns the value of attribute default_content_path.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def default_content_path
  @default_content_path
end

#index_asObject

Always co-erce :index_as attributes into an Array



149
150
151
# File 'lib/om/xml/term.rb', line 149

def index_as
  @index_as
end

#internal_xmlObject

Returns the value of attribute internal_xml.



13
14
15
# File 'lib/om/xml/term.rb', line 13

def internal_xml
  @internal_xml
end

#is_root_termObject

Returns the value of attribute is_root_term.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def is_root_term
  @is_root_term
end

#nameObject

Returns the value of attribute name.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def name
  @name
end

#namespace_prefixObject

Namespace Prefix (xmlns) for the Term.

By default, OM assumes that all terms in a Terminology have the namespace set in the root of the document. If you want to set a different namespace for a Term, pass :namespace_prefix into its initializer (or call .namespace_prefix= on its builder) If a node has no namespace, you must explicitly set namespace_prefix to nil. Currently you have to do this on each term, you can’t set namespace_prefix to nil for an entire Terminology.

Examples:

# For xml like this
<foo xmlns="http://foo.com/schemas/fooschema" xmlns:bar="http://bar.com/schemas/barschema">
  <address>1400 Pennsylvania Avenue</address>
  <bar:latitude>56</bar:latitude>
</foo>

# The Terminology would look like this
OM::XML::Terminology::Builder.new do |t|
  t.root(:name=>:foo, :path=>"foo", :xmlns=>"http://foo.com/schemas/fooschema", "xmlns:bar"=>"http://bar.com/schemas/barschema")
  t.address
  t.latitude(:namespace_prefix=>"bar")
end


42
43
44
# File 'lib/om/xml/term.rb', line 42

def namespace_prefix
  @namespace_prefix
end

#pathObject

Returns the value of attribute path.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def path
  @path
end

#requiredObject

Returns the value of attribute required.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def required
  @required
end

#terminologyObject

Returns the value of attribute terminology.



13
14
15
# File 'lib/om/xml/term.rb', line 13

def terminology
  @terminology
end

#typeObject

Returns the value of attribute type.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def type
  @type
end

#variant_ofObject

Returns the value of attribute variant_of.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def variant_of
  @variant_of
end

#xpathObject

Returns the value of attribute xpath.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def xpath
  @xpath
end

#xpath_constrainedObject

Returns the value of attribute xpath_constrained.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def xpath_constrained
  @xpath_constrained
end

#xpath_relativeObject

Returns the value of attribute xpath_relative.



12
13
14
# File 'lib/om/xml/term.rb', line 12

def xpath_relative
  @xpath_relative
end

Class Method Details

.from_node(mapper_xml) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/om/xml/term.rb', line 124

def self.from_node(mapper_xml)
  name = mapper_xml.attribute("name").text.to_sym
  attributes = {}
  mapper_xml.xpath("./attribute").each do |a|
    attributes[a.attribute("name").text.to_sym] = a.attribute("value").text
  end
  new_mapper = self.new(name, :attributes=>attributes)
  [:index_as, :required, :type, :variant_of, :path, :default_content_path, :namespace_prefix].each do |accessor_name|
    attribute =  mapper_xml.attribute(accessor_name.to_s)
    unless attribute.nil?
      new_mapper.instance_variable_set("@#{accessor_name}", attribute.text )
    end
  end
  new_mapper.internal_xml = mapper_xml

  mapper_xml.xpath("./mapper").each do |child_node|
    child = self.from_node(child_node)
    new_mapper.add_child(child)
  end

  return new_mapper
end

Instance Method Details

#deserialize(val) ⇒ String, ...

Parameters:

  • val (String)

    the value (from xml) to deserialize into the correct object type.

Returns:

  • (String, Date, Integer)


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/om/xml/term.rb', line 106

def deserialize(val)
  case type
  when :date
    #TODO use present?
    val.map { |v| !v.empty? ? Date.parse(v) : nil}
  when :time
    #TODO use present?
    val.map { |v| !v.empty? ? DateTime.parse(v) : nil}
  when :integer
    #TODO use blank?
    val.map { |v| v.empty? ? nil : v.to_i}
  when :boolean
    val.map { |v| v == 'true' }
  else 
    val
  end
end

#generate_xpath_queries!Object

Generates absolute, relative, and constrained xpaths for the term, setting xpath, xpath_relative, and xpath_constrained accordingly. Also triggers update_xpath_values! on all child nodes, as their absolute paths rely on those of their parent nodes.



227
228
229
230
231
232
233
# File 'lib/om/xml/term.rb', line 227

def generate_xpath_queries!
  self.xpath = OM::XML::TermXpathGenerator.generate_absolute_xpath(self)
  self.xpath_constrained = OM::XML::TermXpathGenerator.generate_constrained_xpath(self)
  self.xpath_relative = OM::XML::TermXpathGenerator.generate_relative_xpath(self)
  self.children.each_value {|child| child.generate_xpath_queries! }
  return self
end

#is_root_term?Boolean

Returns:

  • (Boolean)


172
173
174
# File 'lib/om/xml/term.rb', line 172

def is_root_term?
  @is_root_term == true
end

#retrieve_term(*pointers) ⇒ Object

crawl down into mapper’s children hash to find the desired mapper ie. @test_mapper.retrieve_mapper(:conference, :role, :text)



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/om/xml/term.rb', line 155

def retrieve_term(*pointers)
  children_hash = self.children
  pointers.each do |p|
    if children_hash.has_key?(p)
      target = children_hash[p]
      if pointers.index(p) == pointers.length-1
        return target
      else
        children_hash = target.children
      end
    else
      return nil
    end
  end
  return target
end

#sanitize_new_values(new_values) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/om/xml/term.rb', line 77

def sanitize_new_values(new_values)
    # Sanitize new_values to always be a hash with indexes
    case new_values
    when Hash
      sanitize_new_values(new_values.values)
    when Array
      new_values.map {|v| serialize(v)}
    else
      [serialize(new_values)]
    end
end

#serialize(val) ⇒ Object

Parameters:

  • val (String, Date, Integer)


90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/om/xml/term.rb', line 90

def serialize (val)
  return if val.nil?
  case type
  when :date, :integer
    val.to_s
  when :time
    val.to_time.utc.iso8601 
  when :boolean
    val.to_s
  else 
    val
  end
end

#to_xml(options = {}, document = Nokogiri::XML::Document.new) ⇒ Nokogiri::XML::Document

Return an XML representation of the Term

Examples:

If :children=>false, skips rendering child Terms

term.to_xml(:children=>false)

You can provide your own Nokogiri document to insert the xml into

doc = Nokogiri::XML::Document.new
term.to_xml({}, document=doc)

Parameters:

  • options (Hash) (defaults to: {})

    the term will be added to it. If :children=>false, skips rendering child Terms

  • document (Nokogiri::XML::Document) (defaults to: Nokogiri::XML::Document.new)

    (optional) document to insert the term xml into

Returns:

  • (Nokogiri::XML::Document)


244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/om/xml/term.rb', line 244

def to_xml(options={}, document=Nokogiri::XML::Document.new)
  builder = Nokogiri::XML::Builder.with(document) do |xml|
    xml.term(:name=>name) {
      if is_root_term?
        xml.is_root_term("true")
      end
      xml.path path
      xml.namespace_prefix namespace_prefix
      unless attributes.nil? || attributes.empty?
        xml.attributes {
          attributes.each_pair do |attribute_name, attribute_value|
            xml.send("#{attribute_name}_".to_sym, attribute_value)
          end
        }
      end
      xml.index_as {
        unless index_as.nil?
          index_as.each  { |index_type| xml.index_type }
        end
      }
      xml.required required
      xml.data_type type
      unless variant_of.nil?
        xml.variant_of variant_of
      end
      unless default_content_path.nil?
        xml.default_content_path default_content_path
      end
      xml.xpath {
        xml.relative xpath_relative
        xml.absolute xpath
        xml.constrained xpath_constrained
      }
      if options.fetch(:children, true)
        xml.children
      end
    }
  end
  doc = builder.doc
  if options.fetch(:children, true)
    children.values.each {|child| child.to_xml(options, doc.xpath("//term[@name=\"#{name}\"]/children").first)}
  end
  return doc
end

#xml_builder_template(extra_opts = {}) ⇒ Object

term_pointers reference to the property you want to generate a builder template for

Parameters:

  • extra_opts (Hash) (defaults to: {})

Options Hash (extra_opts):

  • :attributes (Hash)


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
# File 'lib/om/xml/term.rb', line 183

def xml_builder_template(extra_opts = {})
  extra_attributes = extra_opts.fetch(:attributes, {})

  node_options = []
  node_child_template = ""
  if !self.default_content_path.nil?
    node_child_options = ["\':::builder_new_value:::\'"]
    node_child_template = " { xml.#{self.default_content_path}( #{OM::XML.delimited_list(node_child_options)} ) }"
  else
    node_options = ["\':::builder_new_value:::\'"]
  end
  if !self.attributes.nil?
    self.attributes.merge(extra_attributes).each_pair do |k,v|
      node_options << "\'#{k}\'=>\'#{v}\'" unless v == :none
    end
  end

  builder_ref = if self.path.include?(":")
    "xml['#{self.path[0..path.index(":")-1]}']"
  elsif !self.namespace_prefix.nil? and self.namespace_prefix != 'oxns'
    "xml['#{self.namespace_prefix}']"
  else
    "xml"
  end

  attribute = OM::XML.delimited_list(node_options)

  builder_method = if self.path.include?(":")
    "#{self.path[path.index(":")+1..-1]}( #{attribute} )"
  elsif self.path.include?(".")
    "send(:\\\"#{self.path}\\\",  #{attribute} )"
  elsif self.path.kind_of?(Hash) && self.path[:attribute]
    "@#{self.path[:attribute]}( #{OM::XML.delimited_list(node_options)} )"
  elsif Nokogiri::XML::Builder.method_defined? self.path.to_sym
    "#{self.path}_( #{OM::XML.delimited_list(node_options)} )"
  else
    "#{self.path}( #{OM::XML.delimited_list(node_options)} )"
  end
  template = "#{builder_ref}.#{builder_method}#{node_child_template}"
  return template.gsub( /:::(.*?):::/ ) { '#{'+$1+'}' }
end

#xpath_absoluteObject



176
177
178
# File 'lib/om/xml/term.rb', line 176

def xpath_absolute
  @xpath
end