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

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

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



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

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

- (Object) method_missing(name, *args, &block)



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

def method_missing (name, *args, &block)
  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, &block)
    end
  end
end

Instance Attribute Details

- (Object) addressed_node

Returns the value of attribute addressed_node



32
33
34
# File 'lib/om/xml/dynamic_node.rb', line 32

def addressed_node
  @addressed_node
end

- (Object) index

Returns the value of attribute index



32
33
34
# File 'lib/om/xml/dynamic_node.rb', line 32

def index
  @index
end

- (Object) key

Returns the value of attribute key



32
33
34
# File 'lib/om/xml/dynamic_node.rb', line 32

def key
  @key
end

- (Object) parent

Returns the value of attribute parent



32
33
34
# File 'lib/om/xml/dynamic_node.rb', line 32

def parent
  @parent
end

- (Object) term

Returns the value of attribute term



32
33
34
# File 'lib/om/xml/dynamic_node.rb', line 32

def term
  @term
end

Instance Method Details

- (Object) !=(other)



135
136
137
# File 'lib/om/xml/dynamic_node.rb', line 135

def !=(other)
  val != other
end

- (Object) ==(other)



131
132
133
# File 'lib/om/xml/dynamic_node.rb', line 131

def ==(other)
  other == val
end

- (Object) delete



123
124
125
# File 'lib/om/xml/dynamic_node.rb', line 123

def delete
  nodeset.delete
end

- (Boolean) eql?(other)



139
140
141
# File 'lib/om/xml/dynamic_node.rb', line 139

def eql?(other)
  self == other
end

- (Object) inspect



127
128
129
# File 'lib/om/xml/dynamic_node.rb', line 127

def inspect
  val.inspect
end

- (Object) new_update_node(name, args)



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

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

- (Object) new_update_node_with_index(name, args)



67
68
69
70
71
72
# File 'lib/om/xml/dynamic_node.rb', line 67

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

- (Object) nodeset



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

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

- (Boolean) respond_to?(method)



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

def respond_to?(method)
  super || val.respond_to?(method)
end

- (Object) retrieve_addressed_node

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



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

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

- (Object) term_child_by_name(term, name)



100
101
102
103
104
105
106
# File 'lib/om/xml/dynamic_node.rb', line 100

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

- (Object) to_pointer



143
144
145
146
147
148
149
# File 'lib/om/xml/dynamic_node.rb', line 143

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

- (Array) val

This resolves the target of this dynamic node into a reified Array



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

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

- (Object) val=(args)



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/om/xml/dynamic_node.rb', line 74

def val=(args)
  @document.ng_xml_will_change!
  new_values = term.sanitize_new_values(args.first)
  existing_nodes = @document.find_by_xpath(xpath)
  if existing_nodes.length > new_values.length
    starting_index = new_values.length + 1
    starting_index.upto(existing_nodes.size).each do |index|
      @document.term_value_delete select: xpath, child_index: index
    end
  end
  new_values.each_with_index do |z, y|
## If we pass something that already has an index on it, we should be able to add it.
    if existing_nodes[y.to_i].nil?
      parent_pointer = if parent
        parent.to_pointer
      elsif term.is_a? NamedTermProxy
        term.proxy_pointer[0..-2]
      end
      @document.term_values_append(:parent_select=> parent_pointer,:parent_index=>0,:template=>to_pointer,:values=>z)
    else
      @document.term_value_update(xpath, y.to_i, z)
    end
  end
end

- (Object) xpath



151
152
153
154
155
156
157
158
159
# File 'lib/om/xml/dynamic_node.rb', line 151

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