om 1.2.5 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COMMON_OM_PATTERNS.textile +127 -0
- data/GETTING_FANCY.textile +15 -13
- data/GETTING_STARTED.textile +89 -51
- data/QUERYING_DOCUMENTS.textile +30 -25
- data/README.rdoc +5 -1
- data/README.textile +4 -0
- data/lib/om/samples/mods_article.rb +7 -4
- data/lib/om/version.rb +1 -1
- data/lib/om/xml/document.rb +10 -2
- data/lib/om/xml/named_term_proxy.rb +7 -2
- data/lib/om/xml/term.rb +59 -9
- data/lib/om/xml/term_value_operators.rb +3 -0
- data/lib/om/xml/terminology.rb +29 -0
- data/lib/om/xml.rb +3 -0
- data/spec/fixtures/mods_article_terminology.xml +2882 -0
- data/spec/unit/document_spec.rb +12 -0
- data/spec/unit/named_term_proxy_spec.rb +22 -9
- data/spec/unit/term_builder_spec.rb +1 -1
- data/spec/unit/term_spec.rb +20 -3
- data/spec/unit/term_value_operators_spec.rb +24 -0
- data/spec/unit/terminology_spec.rb +5 -5
- data/spec/unit/xml_serialization_spec.rb +63 -0
- metadata +12 -8
- data/VERSION +0 -1
@@ -3,11 +3,15 @@ class OM::Samples::ModsArticle
|
|
3
3
|
include OM::XML::Document
|
4
4
|
|
5
5
|
set_terminology do |t|
|
6
|
-
t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
|
6
|
+
t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd", "xmlns:foo"=>"http://my.custom.namespace")
|
7
7
|
|
8
8
|
|
9
9
|
t.title_info(:path=>"titleInfo") {
|
10
|
-
t.main_title(:index_as=>[:facetable],:path=>"title", :label=>"title")
|
10
|
+
t.main_title(:index_as=>[:facetable],:path=>"title", :label=>"title") {
|
11
|
+
t.main_title_lang(:path=>{:attribute=> "xml:lang"})
|
12
|
+
}
|
13
|
+
t.french_title(:ref=>[:title_info,:main_title], :attributes=>{"xml:lang"=>"fre"})
|
14
|
+
|
11
15
|
t.language(:index_as=>[:facetable],:path=>{:attribute=>"lang"})
|
12
16
|
}
|
13
17
|
t.language{
|
@@ -71,8 +75,7 @@ class OM::Samples::ModsArticle
|
|
71
75
|
t.url(:path=>"url")
|
72
76
|
}
|
73
77
|
t.publication_url(:proxy=>[:location,:url])
|
74
|
-
t.
|
75
|
-
t.title(:proxy=>[:mods,:title_info, :main_title])
|
78
|
+
t.title(:proxy=>[:title_info, :main_title])
|
76
79
|
t.journal_title(:proxy=>[:journal, :title_info, :main_title])
|
77
80
|
end
|
78
81
|
|
data/lib/om/version.rb
CHANGED
data/lib/om/xml/document.rb
CHANGED
@@ -57,8 +57,10 @@ module OM::XML::Document
|
|
57
57
|
|
58
58
|
|
59
59
|
# +term_pointer+ Variable length array of values in format [:accessor_name, :accessor_name ...] or [{:accessor_name=>index}, :accessor_name ...]
|
60
|
-
# example:
|
61
|
-
#
|
60
|
+
# @example:
|
61
|
+
# find_by_terms( {:person => 1}, :first_name )
|
62
|
+
# @example
|
63
|
+
# find_by_terms( [:person, 1, :first_name] )
|
62
64
|
# Currently, indexes must be integers.
|
63
65
|
def find_by_terms(*term_pointer)
|
64
66
|
xpath = self.class.terminology.xpath_with_indexes(*term_pointer)
|
@@ -68,6 +70,12 @@ module OM::XML::Document
|
|
68
70
|
return ng_xml.xpath(xpath, ox_namespaces)
|
69
71
|
end
|
70
72
|
end
|
73
|
+
|
74
|
+
# Test whether the document has a node corresponding to the given term_pointer
|
75
|
+
# @param [Array] term_pointer to test
|
76
|
+
def node_exists?(*term_pointer)
|
77
|
+
!find_by_terms(*term_pointer).empty?
|
78
|
+
end
|
71
79
|
|
72
80
|
# Access the class's template registry
|
73
81
|
def template_registry
|
@@ -23,9 +23,14 @@ class OM::XML::NamedTermProxy
|
|
23
23
|
|
24
24
|
def proxied_term
|
25
25
|
if self.parent.nil?
|
26
|
-
self.terminology.retrieve_term(*self.proxy_pointer)
|
26
|
+
pt = self.terminology.retrieve_term(*self.proxy_pointer)
|
27
27
|
else
|
28
|
-
self.parent.retrieve_term(*self.proxy_pointer)
|
28
|
+
pt = self.parent.retrieve_term(*self.proxy_pointer)
|
29
|
+
end
|
30
|
+
if pt.nil?
|
31
|
+
raise OM::XML::Terminology::BadPointerError "The #{name} proxy term points to #{proxy_pointer.inspect} but that term doesn't exist."
|
32
|
+
else
|
33
|
+
return pt
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
data/lib/om/xml/term.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
# Special options:
|
2
|
-
#
|
1
|
+
# Special options:
|
2
|
+
# data_type, index_as, attributes,
|
3
|
+
# is_root_term, required
|
3
4
|
#
|
4
5
|
class OM::XML::Term
|
5
6
|
|
@@ -38,12 +39,7 @@ class OM::XML::Term
|
|
38
39
|
if self.terminology_builder.nil?
|
39
40
|
raise "Cannot perform lookup_ref for the #{self.name} builder. It doesn't have a reference to any terminology builder"
|
40
41
|
end
|
41
|
-
|
42
|
-
target = self.terminology_builder.retrieve_term_builder(*@settings[:ref])
|
43
|
-
rescue OM::XML::Terminology::BadPointerError
|
44
|
-
# Clarify message on BadPointerErrors
|
45
|
-
raise OM::XML::Terminology::BadPointerError, "#{self.name} refers to a Term Builder that doesn't exist. The bad pointer is #{@settings[:ref].inspect}"
|
46
|
-
end
|
42
|
+
target = self.terminology_builder.retrieve_term_builder(*@settings[:ref])
|
47
43
|
|
48
44
|
# Fail on circular references and return an intelligible error message
|
49
45
|
if nodes_visited.include?(target)
|
@@ -216,7 +212,7 @@ class OM::XML::Term
|
|
216
212
|
end
|
217
213
|
if !self.attributes.nil?
|
218
214
|
self.attributes.merge(extra_attributes).each_pair do |k,v|
|
219
|
-
node_options << "
|
215
|
+
node_options << "\'#{k}\'=>\'#{v}\'"
|
220
216
|
end
|
221
217
|
end
|
222
218
|
template = "xml.#{self.path}( #{OM::XML.delimited_list(node_options)} )" + node_child_template
|
@@ -233,6 +229,60 @@ class OM::XML::Term
|
|
233
229
|
return self
|
234
230
|
end
|
235
231
|
|
232
|
+
# Return an XML representation of the Term
|
233
|
+
# @param [Hash] options, the term will be added to it. If :children=>false, skips rendering child Terms
|
234
|
+
# @param [Nokogiri::XML::Document] (optional) document to insert the term xml into
|
235
|
+
# @return [Nokogiri::XML::Document]
|
236
|
+
# @example If :children=>false, skips rendering child Terms
|
237
|
+
# term.to_xml(:children=>false)
|
238
|
+
# @example You can provide your own Nokogiri document to insert the xml into
|
239
|
+
# doc = Nokogiri::XML::Document.new
|
240
|
+
# term.to_xml({}, document=doc)
|
241
|
+
def to_xml(options={}, document=Nokogiri::XML::Document.new)
|
242
|
+
builder = Nokogiri::XML::Builder.with(document) do |xml|
|
243
|
+
xml.term(:name=>name) {
|
244
|
+
if is_root_term?
|
245
|
+
xml.is_root_term("true")
|
246
|
+
end
|
247
|
+
xml.path path
|
248
|
+
xml.namespace_prefix namespace_prefix
|
249
|
+
unless attributes.nil? || attributes.empty?
|
250
|
+
xml.attributes {
|
251
|
+
attributes.each_pair do |attribute_name, attribute_value|
|
252
|
+
xml.send("#{attribute_name}_".to_sym, attribute_value)
|
253
|
+
end
|
254
|
+
}
|
255
|
+
end
|
256
|
+
xml.index_as {
|
257
|
+
unless index_as.nil?
|
258
|
+
index_as.each { |index_type| xml.index_type }
|
259
|
+
end
|
260
|
+
}
|
261
|
+
xml.required required
|
262
|
+
xml.data_type data_type
|
263
|
+
unless variant_of.nil?
|
264
|
+
xml.variant_of variant_of
|
265
|
+
end
|
266
|
+
unless default_content_path.nil?
|
267
|
+
xml.default_content_path default_content_path
|
268
|
+
end
|
269
|
+
xml.xpath {
|
270
|
+
xml.relative xpath_relative
|
271
|
+
xml.absolute xpath
|
272
|
+
xml.constrained xpath_constrained
|
273
|
+
}
|
274
|
+
if options.fetch(:children, true)
|
275
|
+
xml.children
|
276
|
+
end
|
277
|
+
}
|
278
|
+
end
|
279
|
+
doc = builder.doc
|
280
|
+
if options.fetch(:children, true)
|
281
|
+
children.values.each {|child| child.to_xml(options, doc.xpath("//term[@name=\"#{name}\"]/children").first)}
|
282
|
+
end
|
283
|
+
return doc
|
284
|
+
end
|
285
|
+
|
236
286
|
# private :update_xpath_values
|
237
287
|
|
238
288
|
end
|
@@ -161,6 +161,9 @@ module OM::XML::TermValueOperators
|
|
161
161
|
until !starting_point.empty?
|
162
162
|
to_build = [parent_select.pop] + to_build
|
163
163
|
starting_point = find_by_terms(*parent_select)
|
164
|
+
if starting_point.empty? && parent_select.empty?
|
165
|
+
raise OM::XML::TemplateMissingException, "Cannot insert nodes into the document because it is empty."
|
166
|
+
end
|
164
167
|
end
|
165
168
|
to_build.each do |term_pointer|
|
166
169
|
parent_select << term_pointer
|
data/lib/om/xml/terminology.rb
CHANGED
@@ -220,6 +220,35 @@ class OM::XML::Terminology
|
|
220
220
|
terms.values.select {|term| term.is_root_term? }
|
221
221
|
end
|
222
222
|
|
223
|
+
# Return an XML representation of the Terminology and its terms
|
224
|
+
# @param [Hash] options, the term will be added to it. If :children=>false, skips rendering child Terms
|
225
|
+
# @param [Nokogiri::XML::Document] (optional) document to insert the term xml into
|
226
|
+
# @return [Nokogiri::XML::Document]
|
227
|
+
# @example If :children=>false, skips rendering child Terms
|
228
|
+
# terminology.to_xml(:children=>false)
|
229
|
+
# @example You can provide your own Nokogiri document to insert the xml into
|
230
|
+
# doc = Nokogiri::XML::Document.new
|
231
|
+
# terminology.to_xml({}, document=doc)
|
232
|
+
def to_xml(options={}, document=Nokogiri::XML::Document.new)
|
233
|
+
builder = Nokogiri::XML::Builder.with(document) do |xml|
|
234
|
+
xml.terminology {
|
235
|
+
xml.schema schema
|
236
|
+
xml.namespaces {
|
237
|
+
namespaces.each_pair do |ns_name, ns_value|
|
238
|
+
xml.namespace {
|
239
|
+
xml.name ns_name
|
240
|
+
xml.identifier ns_value
|
241
|
+
}
|
242
|
+
end
|
243
|
+
}
|
244
|
+
xml.terms
|
245
|
+
}
|
246
|
+
end
|
247
|
+
document = builder.doc
|
248
|
+
terms.values.each {|term| term.to_xml(options,document.xpath("//terms").first)}
|
249
|
+
return document
|
250
|
+
end
|
251
|
+
|
223
252
|
def self.term_generic_name(*pointers)
|
224
253
|
pointers_to_flat_array(pointers, false).join("_")
|
225
254
|
end
|
data/lib/om/xml.rb
CHANGED
@@ -13,6 +13,9 @@ require "om/xml/template_registry"
|
|
13
13
|
|
14
14
|
module OM::XML
|
15
15
|
|
16
|
+
# Raised when the XML document or XML template can't be found during an operation
|
17
|
+
class TemplateMissingException < StandardError; end
|
18
|
+
|
16
19
|
attr_accessor :ng_xml
|
17
20
|
|
18
21
|
# Module Methods -- These methods can be called directly on the Module itself
|