Class: OM::XML::DynamicNode

Inherits:
Object
  • Object
show all
Defined in:
lib/om/xml/dynamic_node.rb

Overview

Provides a natural syntax for using OM Terminologies to access values from xml Documents

Note: All of these examples assume that @article is an instance of OM::Samples::ModsArticle. Look at that file to see the Terminology.

Examples:

Return an array of the value(s) “start page” node(s) from the second issue node within the first journal node

# Using DynamicNode syntax:
@article.journal(0).issue(1).pages.start
# Other ways to perform this query:
@article.find_by_terms({:journal => 0}, {:issue => 1}, :pages, :start)
@article.ng_xml.xpath("//oxns:relatedItem[@type=\"host\"]/oxns:part[2]/extent[@unit="pages"]", {"oxns"=>"http://www.loc.gov/mods/v3"})

Return an NodeSet of the _first titles_ of all journal nodes

# Using DynamicNode syntax:
@article.journal.title(1)
# Other ways to perform this query:
@article.find_by_terms(:journal, {:title => 1})
@article.ng_xml.xpath("//oxns:relatedItem[@type=\"host\"]/oxns:titleInfo/oxns:title[1]", {"oxns"=>"http://www.loc.gov/mods/v3"})

Find all of the titles from all journals & return the first title Node from that NodeSet

# Using DynamicNode syntax:
@article.journal.title[1]
# Other ways to perform this query:
@article.find_by_terms(:journal, :title)[1]
@article.ng_xml.xpath("//oxns:relatedItem[@type=\"host\"]/oxns:titleInfo/oxns:title", {"oxns"=>"http://www.loc.gov/mods/v3"})[1]

Defined Under Namespace

Classes: AddressedNode

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, index, document, term, parent = nil) ⇒ DynamicNode

TODO a real term object in here would make it easier to lookup



31
32
33
34
35
36
37
# File 'lib/om/xml/dynamic_node.rb', line 31

def initialize(key, index, document, term, parent=nil)  ##TODO a real term object in here would make it easier to lookup
  self.key = key
  self.index = index
  @document = document
  self.term = term
  self.parent = parent
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/om/xml/dynamic_node.rb', line 39

def method_missing (name, *args)
  if /=$/.match(name.to_s)
    new_update_node(name, args)
  elsif args.length > 1
    new_update_node_with_index(name, args)
  else
    child =  term_child_by_name(term.nil? ? parent.term : term, name)
    if child
      OM::XML::DynamicNode.new(name, args.first, @document, child, self)
    else 
      val.send(name, *args)
    end
  end
end

Instance Attribute Details

#addressed_nodeObject

Returns the value of attribute addressed_node.



30
31
32
# File 'lib/om/xml/dynamic_node.rb', line 30

def addressed_node
  @addressed_node
end

#indexObject

Returns the value of attribute index.



30
31
32
# File 'lib/om/xml/dynamic_node.rb', line 30

def index
  @index
end

#keyObject

Returns the value of attribute key.



30
31
32
# File 'lib/om/xml/dynamic_node.rb', line 30

def key
  @key
end

#parentObject

Returns the value of attribute parent.



30
31
32
# File 'lib/om/xml/dynamic_node.rb', line 30

def parent
  @parent
end

#termObject

Returns the value of attribute term.



30
31
32
# File 'lib/om/xml/dynamic_node.rb', line 30

def term
  @term
end

Instance Method Details

#==(other) ⇒ Object



121
122
123
# File 'lib/om/xml/dynamic_node.rb', line 121

def ==(other)
  val == other
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/om/xml/dynamic_node.rb', line 125

def eql?(other)
  self == other
end

#inspectObject



117
118
119
# File 'lib/om/xml/dynamic_node.rb', line 117

def inspect
  val.inspect
end

#new_update_node(name, args) ⇒ Object



54
55
56
57
58
59
# File 'lib/om/xml/dynamic_node.rb', line 54

def new_update_node(name, args)
  modified_name = name.to_s.chop.to_sym
  child = term.retrieve_term(modified_name)
  node = OM::XML::DynamicNode.new(modified_name, nil, @document, child, self)
  node.val=args
end

#new_update_node_with_index(name, args) ⇒ Object



61
62
63
64
65
66
# File 'lib/om/xml/dynamic_node.rb', line 61

def new_update_node_with_index(name, args)
  index = args.shift
  child = term.retrieve_term(name)
  node = OM::XML::DynamicNode.new(name, index, @document, child, self)
  node.val=args
end

#nodesetObject



111
112
113
114
115
# File 'lib/om/xml/dynamic_node.rb', line 111

def nodeset
  query = xpath
  trim_text = !query.index("text()").nil?
  return @document.find_by_xpath(query)
end

#retrieve_addressed_nodeObject

This is very similar to Terminology#retrieve_term, however it expands proxy paths out into their cannonical paths



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

def retrieve_addressed_node()
   chain = []
      
   if parent
     chain += parent.retrieve_addressed_node()
   end
   if (self.index)
     ### This is an index
     node = AddressedNode.new(key, term.xpath_relative, self)
     node.xpath = OM::XML::TermXpathGenerator.add_node_index_predicate(node.xpath, index)
     chain << node
   elsif (term.kind_of? NamedTermProxy)
      proxy = term.proxy_pointer.dup
      first = proxy.shift
      p = @document.class.terminology.retrieve_node(*first)
      chain << AddressedNode.new(p, p.xpath_relative, self)
      while !proxy.empty?
        first = proxy.shift
        p = p.retrieve_term(first)
        chain << AddressedNode.new(p, p.xpath_relative, self)
      end
   else 
     chain << AddressedNode.new(key, term.xpath_relative, self)
   end
   chain
end

#sanitize_new_values(new_values) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/om/xml/dynamic_node.rb', line 83

def sanitize_new_values(new_values)
    # Sanitize new_values to always be a hash with indexes
    case new_values
    when Hash
    when Array
      nv = new_values.dup
      new_values = {}
      nv.each {|v| new_values[nv.index(v).to_s] = v}
    else
      new_values = {"0"=>new_values}
    end
    new_values
end

#term_child_by_name(term, name) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/om/xml/dynamic_node.rb', line 97

def term_child_by_name(term, name)
  if (term.kind_of? NamedTermProxy)
     @document.class.terminology.retrieve_node(*(term.proxy_pointer.dup << name)) 
  else
    term.retrieve_term(name)
  end
end

#to_pointerObject



129
130
131
132
133
134
135
# File 'lib/om/xml/dynamic_node.rb', line 129

def to_pointer
  if self.index
    parent.nil? ?  [{key => index}] : parent.to_pointer << {key => index}
  else ### A pointer
    parent.nil? ? [key] : parent.to_pointer << key
  end
end

#valObject



105
106
107
108
109
# File 'lib/om/xml/dynamic_node.rb', line 105

def val 
  query = xpath
  trim_text = !query.index("text()").nil?
  return @document.find_by_xpath(query).collect {|node| (trim_text ? node.text.strip : node.text) }
end

#val=(args) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/om/xml/dynamic_node.rb', line 68

def val=(args)
  new_values = sanitize_new_values(args.first)
  new_values.each do |y,z|   
## If we pass something that already has an index on it, we should be able to add it.
    if @document.find_by_xpath(xpath)[y.to_i].nil? || y.to_i == -1
      @document.term_values_append(:parent_select=> parent.to_pointer,:parent_index=>0,:template=>to_pointer,:values=>z)
    else
      @document.term_value_update(xpath, y.to_i, z)
    end
  end
  if @document.respond_to?(:dirty=)
    @document.dirty = true
  end
end

#xpathObject



137
138
139
140
141
142
143
144
145
# File 'lib/om/xml/dynamic_node.rb', line 137

def xpath
  if parent.nil?
    @document.class.terminology.xpath_with_indexes(*(to_pointer << {})) ### last element is always filters
  else
    chain = retrieve_addressed_node( )
    '//' + chain.map { |n| n.xpath}.join('/')
  end
  
end