talia_core 0.5.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/config/talia_core.yml.example +37 -35
- data/generators/talia_admin/templates/app/models/fake_source.rb +93 -0
- data/generators/talia_admin/templates/app/models/talia_collection.rb +13 -37
- data/generators/talia_base/talia_base_generator.rb +0 -1
- data/generators/talia_base/templates/app/controllers/custom_templates_controller.rb +2 -1
- data/generators/talia_base/templates/app/controllers/sources_controller.rb +1 -1
- data/generators/talia_base/templates/script/configure_talia +56 -73
- data/generators/talia_swicky/talia_swicky_generator.rb +18 -0
- data/generators/talia_swicky/templates/app/controllers/swicky_notebooks_controller.rb +111 -0
- data/generators/talia_swicky/templates/app/helpers/swicky_notebooks_helper.rb +29 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.builder +6 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.html.erb +10 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/show.html.erb +11 -0
- data/generators/talia_swicky/templates/test/fixtures/notebook.rdf +862 -0
- data/generators/talia_swicky/templates/test/functional/swicky_notebooks_controller_test.rb +44 -0
- data/lib/core_ext/boolean.rb +23 -0
- data/lib/core_ext/jdbc_rake_monkeypatch.rb +22 -0
- data/lib/core_ext/nil_class.rb +11 -0
- data/lib/core_ext/object.rb +34 -0
- data/lib/core_ext/string.rb +15 -0
- data/lib/custom_template.rb +3 -1
- data/lib/loader_helper.rb +16 -3
- data/lib/mysql.rb +7 -7
- data/lib/progressbar.rb +2 -2
- data/lib/swicky/exhibit_json/item.rb +129 -0
- data/lib/swicky/exhibit_json/item_collection.rb +129 -0
- data/lib/swicky/fragment.rb +0 -0
- data/lib/swicky/note.rb +7 -0
- data/lib/swicky/notebook.rb +78 -12
- data/lib/talia_core/active_source.rb +45 -13
- data/lib/talia_core/active_source_parts/class_methods.rb +154 -26
- data/lib/talia_core/active_source_parts/finders.rb +49 -26
- data/lib/talia_core/active_source_parts/predicate_handler.rb +71 -23
- data/lib/talia_core/active_source_parts/rdf/ntriples_reader.rb +13 -0
- data/lib/talia_core/active_source_parts/rdf/rdf_reader.rb +99 -0
- data/lib/talia_core/active_source_parts/rdf/rdfxml_reader.rb +12 -0
- data/lib/talia_core/active_source_parts/{rdf.rb → rdf_handler.rb} +52 -19
- data/lib/talia_core/active_source_parts/xml/generic_reader.rb +151 -260
- data/lib/talia_core/active_source_parts/xml/generic_reader_add_statements.rb +97 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader_helpers.rb +88 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader_import_statements.rb +239 -0
- data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +14 -7
- data/lib/talia_core/active_source_parts/xml/source_builder.rb +7 -3
- data/lib/talia_core/active_source_parts/xml/source_reader.rb +17 -2
- data/lib/talia_core/collection.rb +192 -1
- data/lib/talia_core/data_types/data_loader.rb +88 -18
- data/lib/talia_core/data_types/data_record.rb +24 -2
- data/lib/talia_core/data_types/delayed_copier.rb +13 -3
- data/lib/talia_core/data_types/file_record.rb +24 -13
- data/lib/talia_core/data_types/file_store.rb +111 -94
- data/lib/talia_core/data_types/iip_data.rb +104 -23
- data/lib/talia_core/data_types/iip_loader.rb +102 -56
- data/lib/talia_core/data_types/image_data.rb +3 -1
- data/lib/talia_core/data_types/media_link.rb +4 -1
- data/lib/talia_core/data_types/mime_mapping.rb +65 -38
- data/lib/talia_core/data_types/path_helpers.rb +23 -17
- data/lib/talia_core/data_types/pdf_data.rb +9 -6
- data/lib/talia_core/data_types/simple_text.rb +5 -4
- data/lib/talia_core/data_types/xml_data.rb +53 -25
- data/lib/talia_core/dummy_handler.rb +3 -2
- data/lib/talia_core/errors.rb +13 -27
- data/lib/talia_core/initializer.rb +44 -4
- data/lib/talia_core/oai/active_source_model.rb +13 -6
- data/lib/talia_core/oai/active_source_oai_adapter.rb +13 -12
- data/lib/talia_core/rdf_import.rb +1 -1
- data/lib/talia_core/rdf_resource.rb +2 -1
- data/lib/talia_core/semantic_collection_wrapper.rb +143 -151
- data/lib/talia_core/semantic_property.rb +4 -0
- data/lib/talia_core/semantic_relation.rb +84 -33
- data/lib/talia_core/source.rb +45 -25
- data/lib/talia_core/source_fragment.rb +7 -0
- data/lib/talia_core/source_transfer_object.rb +3 -1
- data/lib/talia_core/source_types/agent.rb +16 -0
- data/lib/talia_core/source_types/dc_resource.rb +3 -3
- data/lib/talia_core/source_types/marcont_resource.rb +15 -0
- data/lib/talia_core/source_types/skos_concept.rb +17 -0
- data/lib/talia_dependencies.rb +1 -1
- data/lib/talia_util.rb +1 -1
- data/lib/talia_util/bar_progressor.rb +1 -1
- data/lib/talia_util/image_conversions.rb +8 -2
- data/lib/talia_util/import_job_helper.rb +40 -3
- data/lib/talia_util/io_helper.rb +15 -4
- data/lib/talia_util/progressable.rb +50 -1
- data/lib/talia_util/rake_tasks.rb +3 -21
- data/lib/talia_util/test_helpers.rb +6 -1
- data/lib/talia_util/util.rb +108 -27
- data/lib/talia_util/xml/base_builder.rb +28 -1
- data/lib/talia_util/xml/rdf_builder.rb +81 -5
- data/lib/tasks/talia_core_tasks.rake +2 -0
- data/test/core_ext/boolean_test.rb +26 -0
- data/test/core_ext/nil_class_test.rb +14 -0
- data/test/core_ext/object_test.rb +26 -0
- data/test/core_ext/string_test.rb +11 -0
- data/test/swicky/json_encoder_test.rb +51 -42
- data/test/swicky/notebook_test.rb +13 -6
- data/test/talia_core/active_source_finder_interface_test.rb +30 -0
- data/test/talia_core/active_source_test.rb +445 -34
- data/test/talia_core/collection_test.rb +332 -0
- data/test/talia_core/data_types/file_record_test.rb +2 -23
- data/test/talia_core/ntriples_reader_test.rb +49 -0
- data/test/talia_core/rdfxml_reader_test.rb +51 -0
- data/test/talia_core/source_test.rb +12 -0
- data/test/talia_util/import_job_helper_test.rb +19 -12
- metadata +190 -90
- data/config/database.yml +0 -19
- data/config/rdfstore.yml +0 -13
- data/config/talia_core.yml +0 -24
- data/generators/talia_base/templates/migrations/bj_migration.rb +0 -10
- data/lib/JXslt/jxslt.rb +0 -60
- data/lib/swicky/json_encoder.rb +0 -179
- data/lib/talia_core/agent.rb +0 -14
- data/lib/talia_core/background_jobs/job.rb +0 -82
- data/lib/talia_core/background_jobs/progress_job.rb +0 -68
- data/lib/talia_core/data_types/temp_file_handling.rb +0 -85
- data/lib/talia_core/ordered_source.rb +0 -228
- data/lib/talia_core/semantic_collection_item.rb +0 -94
- data/lib/talia_core/source_types/collection.rb +0 -15
- data/lib/talia_util/progressbar.rb +0 -236
- data/tasks/talia_core_tasks.rake +0 -2
- data/test/talia_core/ordered_source_test.rb +0 -394
- data/test/talia_core/semantic_collection_item_test.rb +0 -125
@@ -0,0 +1,97 @@
|
|
1
|
+
module TaliaCore
|
2
|
+
module ActiveSourceParts
|
3
|
+
module Xml
|
4
|
+
|
5
|
+
# These are statements that can be used in handlers
|
6
|
+
# (see GenericReaderImportStatements to learn about handlers). They will
|
7
|
+
# add data to the source that is currently being imported.
|
8
|
+
module GenericReaderAddStatements
|
9
|
+
|
10
|
+
# Adds a value for the given predicate (may also be a database field). Example:
|
11
|
+
#
|
12
|
+
# add :uri, "http://foobar.org" # Set the uri of the current source to http://foobar.org
|
13
|
+
# add 'dct:creator', ['John Doe', 'Jane Doe'] # Sets the dct:creator property
|
14
|
+
#
|
15
|
+
# To add relations between source, see #add_rel
|
16
|
+
def add(predicate, object, required = false)
|
17
|
+
# We need to check if the object elements are already strings -
|
18
|
+
# otherwise we would *.to_s the PropertyString objects, which would
|
19
|
+
# destroy the metadata in them.
|
20
|
+
if(object.kind_of?(Array))
|
21
|
+
object.each { |obj| set_element(predicate, obj.is_a?(String) ? obj : obj.to_s, required) }
|
22
|
+
else
|
23
|
+
set_element(predicate, object.is_a?(String) ? object : object.to_s, required)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Works as #add, but also encodes the language (and potentially the type of the literal)
|
28
|
+
# into the value.
|
29
|
+
def add_i18n(predicate, object, lang, type=nil)
|
30
|
+
object = object.blank? ? nil : TaliaCore::PropertyString.new(object, lang, type)
|
31
|
+
add(predicate, object)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Adds a date field. This will attempt to parse the original string
|
35
|
+
# and write the result as an ISO 8061 compliant date string. Note
|
36
|
+
# that this won't be able to parse everything you throw at it, though.
|
37
|
+
def add_date(predicate, date, required = false, fmt = nil)
|
38
|
+
add(predicate, to_iso8601(parse_date(date, fmt)), required)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Adds a date interval as an ISO 8061 compliant date string. See
|
42
|
+
# add_date for more info. If only one of the dates is given this
|
43
|
+
# will add a normal date string instead of an interval.
|
44
|
+
def add_date_interval(predicate, start_date, end_date, fmt = nil)
|
45
|
+
return if(start_date.blank? && end_date.blank?)
|
46
|
+
if(start_date.blank?)
|
47
|
+
add_date(predicate, start_date, true, fmt)
|
48
|
+
elsif(end_date.blank?)
|
49
|
+
add_date(predicate, end_date, true, fmt)
|
50
|
+
else
|
51
|
+
add(predicate, "#{to_iso8601(parse_date(start_date, fmt))}/#{to_iso8601(parse_date(end_date, fmt))}", required)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Adds a relation for the given predicate. This works as #add,
|
56
|
+
# but with the difference that it takes an object uri instead of
|
57
|
+
# a literal value. (See the #add method to add literal values):
|
58
|
+
#
|
59
|
+
# add_rel 'dct:create', 'local:John', 'local:Jane'
|
60
|
+
def add_rel(predicate, object, required = false)
|
61
|
+
object = check_objects(object)
|
62
|
+
if(!object)
|
63
|
+
raise(ArgumentError, "Relation with empty object on #{predicate} (#{@current.attributes['uri']}).") if(required)
|
64
|
+
return
|
65
|
+
end
|
66
|
+
if(object.kind_of?(Array))
|
67
|
+
object.each do |obj|
|
68
|
+
raise(ArgumentError, "Cannot add relation on database field <#{predicate}> - <#{object.inspect}>") if(ActiveSource.db_attr?(predicate))
|
69
|
+
set_element(predicate, "<#{irify(obj)}>", required)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
raise(ArgumentError, "Cannot add relation on database field") if(ActiveSource.db_attr?(predicate))
|
73
|
+
set_element(predicate, "<#{irify(object)}>", required)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add a file to the source being imported. See the DataLoader module for a description of
|
78
|
+
# the possible options.
|
79
|
+
#
|
80
|
+
# Note that the import reader will not be able to resolve URLs or file names that are relative
|
81
|
+
# to the original XML file or URL. File names should be absolute (otherwise they'll be treated
|
82
|
+
# as relative to the current Talia working directory), as should be URLs. Furthermore,
|
83
|
+
# the file names/paths must be valid on the machine _where the import takes place_.
|
84
|
+
def add_file(urls, options = {})
|
85
|
+
return if(urls.blank?)
|
86
|
+
urls = [ urls ] unless(urls.is_a?(Array))
|
87
|
+
files = urls.collect { |url| { :url => get_absolute_file_url(url), :options => options } }
|
88
|
+
@current.attributes[:files] = files if(files.size > 0)
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module TaliaCore
|
2
|
+
module ActiveSourceParts
|
3
|
+
module Xml
|
4
|
+
|
5
|
+
# Helper methods that can be used during the import operation
|
6
|
+
module GenericReaderHelpers
|
7
|
+
|
8
|
+
# Returns true if the given source was already imported. This can return false
|
9
|
+
# if you call this for the currently importing source.
|
10
|
+
def source_exists?(uri)
|
11
|
+
!@sources[uri].blank?
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if the currently imported element already contains type information
|
15
|
+
# AND is of the given type.
|
16
|
+
def current_is_a?(type)
|
17
|
+
assit_kind_of(Class, type)
|
18
|
+
@current.attributes['type'] && ("TaliaCore::#{@current.attributes['type']}".constantize <= type)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get the iso8601 string for the date
|
22
|
+
def to_iso8601(date)
|
23
|
+
return nil unless(date)
|
24
|
+
date = DateTime.parse(date) unless(date.respond_to?(:strftime))
|
25
|
+
date.strftime('%Y-%m-%dT%H:%M:%SZ')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Parses the given string and returns it as a date object
|
29
|
+
def parse_date(date, fmt = nil)
|
30
|
+
return nil if(date.blank?)
|
31
|
+
return DateTime.strptime(date, fmt) if(fmt) # format given
|
32
|
+
return DateTime.new(date.to_i) if(date.size < 5) # this short should be a year
|
33
|
+
DateTime.parse(date)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Gets an absolute path to the given file url, using the base_file_url
|
37
|
+
def get_absolute_file_url(url)
|
38
|
+
orig_url = url.to_s.strip
|
39
|
+
|
40
|
+
url = file_url(orig_url)
|
41
|
+
# If a file:// was stripped from the url, this means it will always point
|
42
|
+
# to a file
|
43
|
+
force_file = (orig_url != url)
|
44
|
+
# Indicates wether the base url is a network url or a file/directory
|
45
|
+
base_is_net = !base_file_url.is_a?(String)
|
46
|
+
# Try to find if we have a "net" URL if we aren't sure if this is a file. In
|
47
|
+
# case the base url is a network url, we'll always assume that the
|
48
|
+
# url is also a net thing. Otherwise we only have a net url if it contains a
|
49
|
+
# '://' string
|
50
|
+
is_net_url = !force_file && (base_is_net || url.include?('://'))
|
51
|
+
# The url is absolute if there is a : character to be found
|
52
|
+
|
53
|
+
|
54
|
+
if(is_net_url)
|
55
|
+
base_is_net ? join_url(base_file_url, url) : url
|
56
|
+
else
|
57
|
+
base_is_net ? url : join_files(base_file_url, url)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Joins the two files. If the path is an absolute path,
|
62
|
+
# the base_dir is ignored
|
63
|
+
def join_files(base_dir, path)
|
64
|
+
if(Pathname.new(path).relative?)
|
65
|
+
File.join(base_dir, path)
|
66
|
+
else
|
67
|
+
path
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Joins the two url parts. If the path is an absolute URL,
|
72
|
+
# the base_url is ignored.
|
73
|
+
def join_url(base_url, path)
|
74
|
+
return path if(path.include?(':')) # Absolute URL contains ':'
|
75
|
+
if(path[0..0] == '/')
|
76
|
+
new_url = base_url.clone
|
77
|
+
new_url.path = path
|
78
|
+
new_url.to_s
|
79
|
+
else
|
80
|
+
(base_file_url + path).to_s
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
module TaliaCore
|
2
|
+
module ActiveSourceParts
|
3
|
+
module Xml
|
4
|
+
|
5
|
+
# These are the statements that are use to add handler for elements or which are
|
6
|
+
# used to otherwise read data for the element
|
7
|
+
#
|
8
|
+
# = What is an element handler?
|
9
|
+
#
|
10
|
+
# The methods in the Handlers submodule create element handlers. Handlers are the
|
11
|
+
# starting point for the import operation and are the only statements at the top
|
12
|
+
# level of the import description.
|
13
|
+
#
|
14
|
+
# Each handler will match a specific XML tag in the "current" XML content. At the
|
15
|
+
# beginning of the import the "current" content will be either the root element
|
16
|
+
# or all of its child elements (depending on wether the can_use_root flag is set).
|
17
|
+
#
|
18
|
+
# The handlers will automatically attempt to match the element(s) at the starting
|
19
|
+
# level:
|
20
|
+
#
|
21
|
+
# class SampleReader < GenericReader
|
22
|
+
#
|
23
|
+
# can_use_root CAN_BE_TRUE_OR_FALSE
|
24
|
+
#
|
25
|
+
# element :foo do
|
26
|
+
# # Code for foo tags
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# element :bar
|
30
|
+
# # Code for bar tags
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# element :foobar
|
34
|
+
# # Code for foobar tags
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# With this importer, there would be three handlers, for "foo", "bar" and
|
40
|
+
# "foobar" tags. If you had the following XML
|
41
|
+
#
|
42
|
+
# <foobar>
|
43
|
+
# <foo>Hello</foo>
|
44
|
+
# <bar>World</bar>
|
45
|
+
# </foobar>
|
46
|
+
#
|
47
|
+
# When reader above is run on the sample XML, the follwoing will happen:
|
48
|
+
#
|
49
|
+
# * In case can_use_root has been set to true, the importer will start
|
50
|
+
# at the root element. In this case, the "Code for foobar tags" will
|
51
|
+
# be executed
|
52
|
+
# * In case can_use_root has not been set, or set to false, the importer
|
53
|
+
# will work on the elements _inside_ the root tag. This means that
|
54
|
+
# it will first check the "foo" tag and call the "Code for foo tags"
|
55
|
+
# and then check the the "bar" tag and call the "Code for bar tags".
|
56
|
+
#
|
57
|
+
# Obviously an XML can also contain the same element multiple times, in
|
58
|
+
# which case the handler will be called multiple time.
|
59
|
+
#
|
60
|
+
# = What happens inside a handler?
|
61
|
+
#
|
62
|
+
# When a handler is called, the "current" XML will be set to the inner
|
63
|
+
# part of the current document. That is, in case of the "foobar" handler
|
64
|
+
# the "current" XML would consist of the "foo" and "bar" tags (and their)
|
65
|
+
# content. For the "foo" and "bar" handler, the "current" XML would be
|
66
|
+
# just the text nodes inside it.
|
67
|
+
#
|
68
|
+
# The handler handler also has a "current" source that is being imported.
|
69
|
+
# In case of a handler that was declared with .element, a new, empty
|
70
|
+
# source is created whenever the handler is called. If the handler was
|
71
|
+
# declared with .plain_element, the handler "inherits" the current source
|
72
|
+
# that was active when it was called.
|
73
|
+
#
|
74
|
+
# Inside the handler, the GenericReaderAddStatements are used in order
|
75
|
+
# to add data and properties to the current source.
|
76
|
+
#
|
77
|
+
# All handlers are executed as instance methods of the current reader.
|
78
|
+
#
|
79
|
+
# = How are handlers called?
|
80
|
+
#
|
81
|
+
# The handlers that are declared in the importer are
|
82
|
+
# matched against the "starting" tags in the XML and called
|
83
|
+
# automatically. Inside the handler methods like #add_source can be
|
84
|
+
# used to call a handler on sub-elements. Example for the
|
85
|
+
# reader given above (with can_use_root set):
|
86
|
+
#
|
87
|
+
# element :foobar do
|
88
|
+
# # At this point a new empty source has been created
|
89
|
+
# # and is set as the "current" source. The "current" XML
|
90
|
+
# # is the foo and bar tags
|
91
|
+
# add_source :foo # Takes the "foo" tag and calls the handler
|
92
|
+
# add_source :bar # Takes the "bar" tag and calls the handler
|
93
|
+
# # Alternatively: add_source :from_all_sources -> do both automatically
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# If the "foo" hanlder was defined as a .plain_element
|
97
|
+
#
|
98
|
+
# plain_element :foo { }
|
99
|
+
#
|
100
|
+
# then the "foo" handler would inherit the source from the "foobar" handler
|
101
|
+
# through wich it was called.
|
102
|
+
#
|
103
|
+
# = Accessing data within in the handlers
|
104
|
+
#
|
105
|
+
# While the handlers allow you to navigate through the XML structure, you
|
106
|
+
# will also have to read the data in order to construct the sources.
|
107
|
+
#
|
108
|
+
# The from_* methods allow to read data from the current XML:
|
109
|
+
#
|
110
|
+
# element :foobar do
|
111
|
+
# the_thing = from_element :foo
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# In this case, inside the handler for the "foobar" tag, you attempt to
|
115
|
+
# read the text from the :foo element. With the XML given above, the
|
116
|
+
# result of this would be the string "Hello"
|
117
|
+
module GenericReaderImportStatements
|
118
|
+
|
119
|
+
# Methods to create handlers. See GenericReaderImportStatements
|
120
|
+
module Handlers
|
121
|
+
|
122
|
+
# Creates a handler for the element_name tag. Each time the handler
|
123
|
+
# is called, a new, empty source is created and set as current.
|
124
|
+
#
|
125
|
+
# The handler block will be executed as an instance method on the
|
126
|
+
# current reader object and the "current" XML inside the handler
|
127
|
+
# block will be the inner XML of the "element_name" tag that is
|
128
|
+
# currently being processed
|
129
|
+
def element(element_name, &handler_block)
|
130
|
+
element_handler(element_name, true, &handler_block)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Works as #element, except that no new source is created. The
|
134
|
+
# current source in the block will be the one that is active
|
135
|
+
# at the point where the handler was called.
|
136
|
+
def plain_element(element_name, &handler_block)
|
137
|
+
element_handler(element_name, false, &handler_block)
|
138
|
+
end
|
139
|
+
|
140
|
+
end # End handlers
|
141
|
+
|
142
|
+
# Gets the data for an attribute of the current XML element. E.g. if
|
143
|
+
# you have XML for
|
144
|
+
#
|
145
|
+
# <foobar name="myself">
|
146
|
+
# <foo>Hello World</foo>
|
147
|
+
# </foobar>
|
148
|
+
#
|
149
|
+
# And this handler
|
150
|
+
#
|
151
|
+
# element :foobar do
|
152
|
+
# my_attr = from_attribute :name
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# then the my_attr variable will be set to "myself"
|
156
|
+
def from_attribute(attrib)
|
157
|
+
@current.element[attrib]
|
158
|
+
end
|
159
|
+
|
160
|
+
# Gets data from the XML tag "elem" inside the currently active XML
|
161
|
+
#
|
162
|
+
# <foobar><foo>Hello World</foo></foobar>
|
163
|
+
#
|
164
|
+
# Inside the "foobar" handler `from_element :foo` would return
|
165
|
+
# "Hello World" with the XML given above.
|
166
|
+
def from_element(elem)
|
167
|
+
return @current.element.inner_text.strip if(elem == :self)
|
168
|
+
elements = all_elements(elem)
|
169
|
+
elements = elements.uniq if(elements.size > 1) # Try to ignore dupes
|
170
|
+
raise(ArgumentError, "More than one element of #{elem} in #{@current.element.inspect}") if(elements.size > 1)
|
171
|
+
elements.first
|
172
|
+
end
|
173
|
+
|
174
|
+
# This works like #from_element, except that it will return an array with the
|
175
|
+
# values of *all* "elem" tags inside the current XML.
|
176
|
+
def all_elements(elem)
|
177
|
+
result = []
|
178
|
+
@current.element.search("/#{elem}").each { |el| result << el.inner_text.strip }
|
179
|
+
result
|
180
|
+
end
|
181
|
+
|
182
|
+
# Adds a nested element. This will not change the currently importing source, but
|
183
|
+
# it will set the currently active XML to the nested element.
|
184
|
+
# If a block is given, it will execute for each of the nested elements that
|
185
|
+
# are found. Otherwise, a method name must be given, and that method will
|
186
|
+
# be executed instead of the block
|
187
|
+
def nested(sub_element, handler_method = nil)
|
188
|
+
original_element = @current.element
|
189
|
+
begin
|
190
|
+
@current.element.search("#{sub_element}").each do |sub_elem|
|
191
|
+
@current.element = sub_elem
|
192
|
+
assit(block_given? ^ (handler_method.is_a?(Symbol)), 'Must have either a handler (x)or a block.')
|
193
|
+
block_given? ? yield : self.send(handler_method)
|
194
|
+
end
|
195
|
+
ensure
|
196
|
+
@current.element = original_element
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Adds a source from the given sub-element. You may either pass a block with
|
201
|
+
# the code to import or the name of an already registered element. If the
|
202
|
+
# special value :from_all_sources is given, it will read from all sub-elements for which
|
203
|
+
# there are registered handlers.
|
204
|
+
#
|
205
|
+
# If the method is used with a block, it will call the block as a handler for the _current_
|
206
|
+
# element.l
|
207
|
+
def add_source(sub_element = nil, &block)
|
208
|
+
if(sub_element)
|
209
|
+
if(sub_element == :from_all_sources)
|
210
|
+
read_children_of(@current.element)
|
211
|
+
else
|
212
|
+
@current.element.search("/#{sub_element}").each { |sub_elem| read_source(sub_elem, &block) }
|
213
|
+
end
|
214
|
+
else
|
215
|
+
raise(ArgumentError, "When adding elements on the fly, you must use a block") unless(block)
|
216
|
+
attribs = call_handler(@current.element, &block)
|
217
|
+
add_source_with_check(attribs) if(attribs)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Imports another source like add_source and also assigns the new source as
|
222
|
+
# a part of the current one.
|
223
|
+
def add_part(sub_element = nil, &block)
|
224
|
+
raise(RuntimeError, "Cannot add child before having an uri to refer to.") unless(@current.attributes['uri'])
|
225
|
+
@current.element.search("/#{sub_element}").each do |sub_elem|
|
226
|
+
attribs = call_handler(sub_elem, &block)
|
227
|
+
if(attribs)
|
228
|
+
attribs[N::TALIA.part_of.to_s] ||= []
|
229
|
+
attribs[N::TALIA.part_of.to_s] << "<#{@current.attributes['uri']}>"
|
230
|
+
add_source_with_check(attribs)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -2,15 +2,19 @@ module TaliaCore
|
|
2
2
|
module ActiveSourceParts
|
3
3
|
module Xml
|
4
4
|
|
5
|
-
# Class for creating xml-rdf
|
5
|
+
# Class for creating xml-rdf Data from a source. See the parent class, TaliaUtil::Xml::RdfBuilder, for
|
6
|
+
# more information.
|
6
7
|
class RdfBuilder < TaliaUtil::Xml::RdfBuilder
|
7
8
|
|
9
|
+
# Builds the RDF for a source and returns the result as a string
|
8
10
|
def self.build_source(source)
|
9
11
|
make_xml_string { |build| build.write_source(source) }
|
10
|
-
|
12
|
+
end
|
11
13
|
|
12
|
-
#
|
14
|
+
# Builds the RDF for a source. This will include both the "direct" predicates as well as the
|
15
|
+
# "inverse" (incoming predicates of a source)
|
13
16
|
def write_source(source)
|
17
|
+
# The source is written as subject, with all the triples nested inside it.
|
14
18
|
@builder.rdf :Description, 'rdf:about' => source.uri.to_s do # Element describing this resource
|
15
19
|
# loop through the predicates
|
16
20
|
source.direct_predicates.each do |predicate|
|
@@ -18,6 +22,9 @@ module TaliaCore
|
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
25
|
+
# Each of the inverse properties creates another subject entry, that just contains the one
|
26
|
+
# triple relating it to the current source. (In this case, the subject and predicate entries
|
27
|
+
# aren't merged any further)
|
21
28
|
source.inverse_predicates.each do |predicate|
|
22
29
|
source.inverse[predicate].each do |inverse_subject|
|
23
30
|
@builder.rdf :Description, 'rdf:about' => inverse_subject do
|
@@ -28,7 +35,7 @@ module TaliaCore
|
|
28
35
|
end
|
29
36
|
|
30
37
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|