glossarist 2.6.6 → 2.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +90 -29
- data/glossarist.gemspec +2 -0
- data/lib/glossarist/citation.rb +26 -123
- data/lib/glossarist/cli/compare_command.rb +106 -0
- data/lib/glossarist/cli/export_command.rb +11 -14
- data/lib/glossarist/cli/validate_command.rb +111 -20
- data/lib/glossarist/cli.rb +18 -0
- data/lib/glossarist/collections/bibliography_collection.rb +4 -2
- data/lib/glossarist/collections/localization_collection.rb +2 -0
- data/lib/glossarist/comparison_result.rb +35 -0
- data/lib/glossarist/concept_collector.rb +44 -0
- data/lib/glossarist/concept_comparator.rb +72 -0
- data/lib/glossarist/concept_data.rb +16 -0
- data/lib/glossarist/concept_diff.rb +15 -0
- data/lib/glossarist/concept_document.rb +11 -0
- data/lib/glossarist/concept_manager.rb +19 -5
- data/lib/glossarist/concept_ref.rb +13 -0
- data/lib/glossarist/concept_validator.rb +6 -1
- data/lib/glossarist/context_configuration.rb +90 -0
- data/lib/glossarist/dataset_validator.rb +8 -4
- data/lib/glossarist/designation/prefix.rb +17 -0
- data/lib/glossarist/designation/suffix.rb +17 -0
- data/lib/glossarist/gcr_metadata.rb +7 -14
- data/lib/glossarist/gcr_package.rb +35 -23
- data/lib/glossarist/gcr_validator.rb +38 -17
- data/lib/glossarist/localized_concept.rb +8 -0
- data/lib/glossarist/managed_concept.rb +39 -6
- data/lib/glossarist/managed_concept_data.rb +2 -1
- data/lib/glossarist/rdf/ext/jsonld_transform_ext.rb +208 -0
- data/lib/glossarist/rdf/ext/mapping_ext.rb +37 -0
- data/lib/glossarist/rdf/ext/mapping_rule_ext.rb +27 -0
- data/lib/glossarist/rdf/ext/member_rule_ext.rb +34 -0
- data/lib/glossarist/rdf/ext/turtle_transform_ext.rb +222 -0
- data/lib/glossarist/rdf/ext.rb +39 -0
- data/lib/glossarist/rdf/gloss_citation.rb +36 -0
- data/lib/glossarist/rdf/gloss_concept.rb +58 -0
- data/lib/glossarist/rdf/gloss_concept_date.rb +24 -0
- data/lib/glossarist/rdf/gloss_concept_reference.rb +29 -0
- data/lib/glossarist/rdf/gloss_concept_source.rb +37 -0
- data/lib/glossarist/rdf/gloss_designation.rb +146 -0
- data/lib/glossarist/rdf/gloss_detailed_definition.rb +24 -0
- data/lib/glossarist/rdf/gloss_grammar_info.rb +57 -0
- data/lib/glossarist/rdf/gloss_locality.rb +25 -0
- data/lib/glossarist/rdf/gloss_localized_concept.rb +67 -0
- data/lib/glossarist/rdf/gloss_non_verbal_rep.rb +31 -0
- data/lib/glossarist/rdf/gloss_pronunciation.rb +32 -0
- data/lib/glossarist/rdf/gloss_reference.rb +55 -0
- data/lib/glossarist/rdf/namespaces/glossarist_namespace.rb +12 -0
- data/lib/glossarist/rdf/namespaces/iso_thes_namespace.rb +12 -0
- data/lib/glossarist/rdf/namespaces/owl_namespace.rb +12 -0
- data/lib/glossarist/rdf/namespaces/prov_namespace.rb +12 -0
- data/lib/glossarist/rdf/namespaces/rdf_namespace.rb +12 -0
- data/lib/glossarist/rdf/namespaces/skosxl_namespace.rb +12 -0
- data/lib/glossarist/rdf/namespaces.rb +8 -2
- data/lib/glossarist/rdf/relationships.rb +19 -0
- data/lib/glossarist/rdf/v3/configuration.rb +15 -0
- data/lib/glossarist/rdf/v3.rb +79 -0
- data/lib/glossarist/rdf.rb +22 -2
- data/lib/glossarist/reference_extractor.rb +12 -19
- data/lib/glossarist/reference_resolver.rb +3 -3
- data/lib/glossarist/related_concept.rb +2 -10
- data/lib/glossarist/schema_migration.rb +39 -0
- data/lib/glossarist/sts/term_mapper.rb +2 -2
- data/lib/glossarist/transforms/concept_to_gloss_transform.rb +355 -0
- data/lib/glossarist/transforms.rb +2 -2
- data/lib/glossarist/v1/concept.rb +17 -17
- data/lib/glossarist/v2/citation.rb +36 -0
- data/lib/glossarist/v2/concept_data.rb +46 -0
- data/lib/glossarist/v2/concept_document.rb +18 -0
- data/lib/glossarist/v2/concept_ref.rb +8 -0
- data/lib/glossarist/v2/concept_source.rb +16 -0
- data/lib/glossarist/v2/configuration.rb +13 -0
- data/lib/glossarist/v2/detailed_definition.rb +14 -0
- data/lib/glossarist/v2/localized_concept.rb +9 -0
- data/lib/glossarist/v2/managed_concept.rb +25 -0
- data/lib/glossarist/v2/managed_concept_data.rb +49 -0
- data/lib/glossarist/v2/related_concept.rb +15 -0
- data/lib/glossarist/v2.rb +28 -0
- data/lib/glossarist/v3/bibliography_entry.rb +19 -0
- data/lib/glossarist/v3/bibliography_file.rb +27 -0
- data/lib/glossarist/v3/citation.rb +30 -0
- data/lib/glossarist/v3/concept_data.rb +46 -0
- data/lib/glossarist/v3/concept_document.rb +18 -0
- data/lib/glossarist/v3/concept_ref.rb +8 -0
- data/lib/glossarist/v3/concept_source.rb +16 -0
- data/lib/glossarist/v3/configuration.rb +13 -0
- data/lib/glossarist/v3/detailed_definition.rb +14 -0
- data/lib/glossarist/v3/image_entry.rb +21 -0
- data/lib/glossarist/v3/image_file.rb +31 -0
- data/lib/glossarist/v3/localized_concept.rb +9 -0
- data/lib/glossarist/v3/managed_concept.rb +26 -0
- data/lib/glossarist/v3/managed_concept_data.rb +34 -0
- data/lib/glossarist/v3/related_concept.rb +15 -0
- data/lib/glossarist/v3.rb +36 -0
- data/lib/glossarist/validation/bibliography_index.rb +61 -30
- data/lib/glossarist/validation/rules/asciidoc_xref_rule.rb +2 -15
- data/lib/glossarist/validation/rules/authoritative_source_rule.rb +2 -15
- data/lib/glossarist/validation/rules/base.rb +5 -0
- data/lib/glossarist/validation/rules/bibliography_yaml_rule.rb +2 -3
- data/lib/glossarist/validation/rules/citation_completeness_rule.rb +5 -27
- data/lib/glossarist/validation/rules/dataset_context.rb +8 -3
- data/lib/glossarist/validation/rules/date_validity_rule.rb +1 -1
- data/lib/glossarist/validation/rules/designation_status_rule.rb +0 -1
- data/lib/glossarist/validation/rules/designation_type_rule.rb +1 -5
- data/lib/glossarist/validation/rules/domain_ref_rule.rb +37 -0
- data/lib/glossarist/validation/rules/domain_target_rule.rb +56 -0
- data/lib/glossarist/validation/rules/gcr_context.rb +12 -13
- data/lib/glossarist/validation/rules/image_reference_rule.rb +2 -17
- data/lib/glossarist/validation/rules/locality_completeness_rule.rb +58 -0
- data/lib/glossarist/validation/rules/localization_consistency_rule.rb +72 -0
- data/lib/glossarist/validation/rules/localization_presence_rule.rb +1 -1
- data/lib/glossarist/validation/rules/model_validity_rule.rb +71 -0
- data/lib/glossarist/validation/rules/orphaned_bibliography_rule.rb +1 -13
- data/lib/glossarist/validation/rules/orphaned_images_rule.rb +16 -11
- data/lib/glossarist/validation/rules/ref_shape_rule.rb +68 -0
- data/lib/glossarist/validation/rules/related_concept_cycle_rule.rb +1 -3
- data/lib/glossarist/validation/rules/related_concept_symmetry_rule.rb +1 -3
- data/lib/glossarist/validation/rules/related_concept_target_rule.rb +64 -0
- data/lib/glossarist/validation/rules/schema_version_rule.rb +41 -0
- data/lib/glossarist/validation/rules/source_type_rule.rb +1 -15
- data/lib/glossarist/validation/rules/source_urn_format_rule.rb +65 -0
- data/lib/glossarist/validation/rules/uuid_format_rule.rb +33 -0
- data/lib/glossarist/validation/rules.rb +10 -43
- data/lib/glossarist/validation/validation_issue.rb +14 -11
- data/lib/glossarist/validation_result.rb +12 -22
- data/lib/glossarist/version.rb +1 -1
- data/lib/glossarist.rb +9 -0
- data/memory/project-status.md +43 -0
- data/scripts/migrate_dataset.rb +180 -0
- data/scripts/migrate_isotc204_to_v3.rb +134 -0
- data/scripts/migrate_isotc211_to_v3.rb +153 -0
- data/scripts/migrate_osgeo_to_v3.rb +155 -0
- data/scripts/upgrade_dataset_to_v3.rb +47 -0
- metadata +111 -6
- data/TODO.integration/01-gcr-package-cli.md +0 -180
- data/lib/glossarist/rdf/skos_concept.rb +0 -43
- data/lib/glossarist/rdf/skos_vocabulary.rb +0 -25
- data/lib/glossarist/transforms/concept_to_skos_transform.rb +0 -131
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Extends Lutaml::Rdf::Mapping with support for multiple rdf:type values.
|
|
4
|
+
#
|
|
5
|
+
# Usage in rdf do blocks:
|
|
6
|
+
# type "gloss:Concept" # single type (original API)
|
|
7
|
+
# types "gloss:Concept", "skos:Concept" # multiple types (new API)
|
|
8
|
+
module Lutaml
|
|
9
|
+
module Rdf
|
|
10
|
+
class Mapping
|
|
11
|
+
attr_writer :namespace_set, :rdf_subject, :rdf_type, :rdf_predicates,
|
|
12
|
+
:rdf_members
|
|
13
|
+
|
|
14
|
+
def types(*values)
|
|
15
|
+
@rdf_types = values.flatten.map(&:to_s)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def rdf_types
|
|
19
|
+
if defined?(@rdf_types) && @rdf_types
|
|
20
|
+
@rdf_types
|
|
21
|
+
elsif @rdf_type
|
|
22
|
+
[@rdf_type.to_s]
|
|
23
|
+
else
|
|
24
|
+
[]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def rdf_types=(values)
|
|
29
|
+
@rdf_types = values
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def has_types_or_predicates?
|
|
33
|
+
rdf_types.any? || rdf_predicates.any?
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Extends Lutaml::Rdf::MappingRule with `as:` option for URI-valued predicates.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# predicate :hasStatus, namespace: Ns, to: :status, as: :uri
|
|
7
|
+
# predicate :name, namespace: Ns, to: :name # default: :literal
|
|
8
|
+
module Lutaml
|
|
9
|
+
module Rdf
|
|
10
|
+
class MappingRule
|
|
11
|
+
attr_reader :as
|
|
12
|
+
|
|
13
|
+
def initialize(predicate_name, namespace:, to:, lang_tagged: false, as: :literal)
|
|
14
|
+
validate!(predicate_name, namespace, to)
|
|
15
|
+
@predicate_name = predicate_name.to_s.freeze
|
|
16
|
+
@namespace = namespace
|
|
17
|
+
@to = to
|
|
18
|
+
@lang_tagged = lang_tagged
|
|
19
|
+
@as = as
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def uri_value?
|
|
23
|
+
@as == :uri
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Extends Lutaml::Rdf::MemberRule with `inline:` and `link:` options.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# members :localizations, link: "gloss:hasLocalization"
|
|
7
|
+
# members :designations, link: ->(d) { skosxl_predicate_for(d) }
|
|
8
|
+
# members :definitions, link: "gloss:hasDefinition"
|
|
9
|
+
# members :sources # no linking predicate
|
|
10
|
+
module Lutaml
|
|
11
|
+
module Rdf
|
|
12
|
+
class MemberRule
|
|
13
|
+
attr_reader :attr_name, :inline, :link
|
|
14
|
+
|
|
15
|
+
def initialize(attr_name, inline: true, link: nil)
|
|
16
|
+
@attr_name = attr_name.to_sym
|
|
17
|
+
@inline = inline
|
|
18
|
+
@link = link
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def link_predicate_for(member, mapping)
|
|
22
|
+
return nil unless @link
|
|
23
|
+
|
|
24
|
+
case @link
|
|
25
|
+
when String
|
|
26
|
+
mapping.namespace_set.resolve_compact_iri(@link)
|
|
27
|
+
when Proc
|
|
28
|
+
uri = @link.call(member)
|
|
29
|
+
uri.include?(":") ? mapping.namespace_set.resolve_compact_iri(uri) : uri
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rdf/turtle"
|
|
4
|
+
|
|
5
|
+
# Extends Lutaml::Turtle::Transform to handle:
|
|
6
|
+
# - Multiple rdf:type values (types method)
|
|
7
|
+
# - URI-valued predicates (as: :uri)
|
|
8
|
+
# - Reference-only members (inline: false)
|
|
9
|
+
# - Linking predicates for members (link option)
|
|
10
|
+
# - Recursive prefix collection
|
|
11
|
+
# - Polymorphic member collections
|
|
12
|
+
module Lutaml
|
|
13
|
+
module Turtle
|
|
14
|
+
class Transform < Lutaml::Rdf::Transform
|
|
15
|
+
def model_to_data(instance, _format, options = {})
|
|
16
|
+
mapping = extract_turtle_mapping(options)
|
|
17
|
+
return "" unless mapping
|
|
18
|
+
|
|
19
|
+
if !mapping.rdf_subject && mapping.has_types_or_predicates? && mapping.rdf_members.empty?
|
|
20
|
+
raise MissingSubjectError,
|
|
21
|
+
"Turtle mapping requires a subject block"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
graph = build_graph(mapping, instance)
|
|
25
|
+
return "" if graph.empty?
|
|
26
|
+
|
|
27
|
+
prefixes = collect_all_prefixes(mapping, instance)
|
|
28
|
+
RDF::Turtle::Writer.buffer(prefixes: prefixes) do |writer|
|
|
29
|
+
graph.each_statement { |stmt| writer << stmt }
|
|
30
|
+
end.strip
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def data_to_model(data, _format, options = {})
|
|
34
|
+
mapping = extract_turtle_mapping(options)
|
|
35
|
+
unless mapping&.rdf_subject
|
|
36
|
+
raise MissingSubjectError,
|
|
37
|
+
"Turtle mapping requires a subject block"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
graph = data.is_a?(RDF::Graph) ? data : Lutaml::Turtle::Adapter.parse(data)
|
|
41
|
+
attrs = extract_attributes(graph, mapping)
|
|
42
|
+
build_instance(attrs, options)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def extract_turtle_mapping(options)
|
|
48
|
+
options[:mappings] || mappings_for(:turtle, lutaml_register)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def build_graph(mapping, instance)
|
|
52
|
+
graph = RDF::Graph.new
|
|
53
|
+
|
|
54
|
+
if mapping.has_types_or_predicates?
|
|
55
|
+
subject_uri = if mapping.rdf_subject
|
|
56
|
+
RDF::URI(resolve_subject_uri(mapping, instance))
|
|
57
|
+
else
|
|
58
|
+
RDF::Node.new
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
emit_type_statements(graph, subject_uri, mapping)
|
|
62
|
+
emit_predicate_statements(graph, subject_uri, instance, mapping)
|
|
63
|
+
emit_member_link_statements(graph, subject_uri, instance, mapping)
|
|
64
|
+
emit_relationship_statements(graph, subject_uri, instance)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
emit_child_resources(graph, instance, mapping)
|
|
68
|
+
|
|
69
|
+
graph
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def emit_type_statements(graph, subject_uri, mapping)
|
|
73
|
+
mapping.rdf_types.each do |type_str|
|
|
74
|
+
type_uri = RDF::URI(mapping.namespace_set.resolve_compact_iri(type_str))
|
|
75
|
+
graph << RDF::Statement.new(subject_uri, RDF.type, type_uri)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def emit_predicate_statements(graph, subject_uri, instance, mapping)
|
|
80
|
+
mapping.rdf_predicates.each do |rule|
|
|
81
|
+
value = instance.public_send(rule.to)
|
|
82
|
+
next if value.nil?
|
|
83
|
+
|
|
84
|
+
Array(value).each do |v|
|
|
85
|
+
next if v.is_a?(String) && v.empty?
|
|
86
|
+
|
|
87
|
+
object = build_rdf_object(v, rule, mapping)
|
|
88
|
+
graph << RDF::Statement.new(subject_uri, RDF::URI(rule.uri), object)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def emit_member_link_statements(graph, subject_uri, instance, mapping)
|
|
94
|
+
mapping.rdf_members.each do |member_rule|
|
|
95
|
+
next unless member_rule.link
|
|
96
|
+
|
|
97
|
+
collection = Array(instance.public_send(member_rule.attr_name))
|
|
98
|
+
collection.each do |member|
|
|
99
|
+
child_mapping = member.class.mappings[:turtle]
|
|
100
|
+
next unless child_mapping&.rdf_subject
|
|
101
|
+
|
|
102
|
+
child_uri = RDF::URI(resolve_subject_uri(child_mapping, member))
|
|
103
|
+
link_uri = RDF::URI(member_rule.link_predicate_for(member, mapping))
|
|
104
|
+
next unless link_uri
|
|
105
|
+
|
|
106
|
+
graph << RDF::Statement.new(subject_uri, link_uri, child_uri)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def emit_relationship_statements(graph, subject_uri, instance)
|
|
112
|
+
return unless instance.is_a?(Glossarist::Rdf::Relationships)
|
|
113
|
+
|
|
114
|
+
Array(instance.relationship_triples).each do |pred_uri, obj_uri|
|
|
115
|
+
graph << RDF::Statement.new(subject_uri, RDF::URI(pred_uri), RDF::URI(obj_uri))
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def emit_child_resources(graph, instance, mapping)
|
|
120
|
+
mapping.rdf_members.each do |member_rule|
|
|
121
|
+
collection = Array(instance.public_send(member_rule.attr_name))
|
|
122
|
+
collection.each do |member|
|
|
123
|
+
member_mapping = member.class.mappings[:turtle]
|
|
124
|
+
next unless member_mapping
|
|
125
|
+
|
|
126
|
+
graph << build_graph(member_mapping, member)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def build_rdf_object(value, rule, mapping = nil)
|
|
132
|
+
if rule.uri_value?
|
|
133
|
+
resolved = if mapping && value.include?(":")
|
|
134
|
+
mapping.namespace_set.resolve_compact_iri(value)
|
|
135
|
+
else
|
|
136
|
+
value
|
|
137
|
+
end
|
|
138
|
+
RDF::URI(resolved)
|
|
139
|
+
elsif rule.lang_tagged
|
|
140
|
+
lang = extract_language(value)
|
|
141
|
+
RDF::Literal.new(value.to_s, language: lang)
|
|
142
|
+
else
|
|
143
|
+
case value
|
|
144
|
+
when Integer then RDF::Literal.new(value, datatype: RDF::XSD.integer)
|
|
145
|
+
when Float then RDF::Literal.new(value, datatype: RDF::XSD.double)
|
|
146
|
+
when TrueClass, FalseClass then RDF::Literal.new(value, datatype: RDF::XSD.boolean)
|
|
147
|
+
else RDF::Literal.new(value.to_s)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def collect_all_prefixes(mapping, instance)
|
|
153
|
+
ns_set = collect_namespaces_recursive(mapping, instance)
|
|
154
|
+
ns_set.each.with_object({}) do |ns, h|
|
|
155
|
+
h[ns.prefix.to_sym] = ns.uri if ns.prefix && ns.uri
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def collect_namespaces_recursive(mapping, instance)
|
|
160
|
+
ns_set = mapping.namespace_set
|
|
161
|
+
|
|
162
|
+
mapping.rdf_members.each do |member_rule|
|
|
163
|
+
collection = Array(instance.public_send(member_rule.attr_name))
|
|
164
|
+
next if collection.empty?
|
|
165
|
+
|
|
166
|
+
collection.map(&:class).uniq.each do |klass|
|
|
167
|
+
member_mapping = klass.mappings[:turtle]
|
|
168
|
+
next unless member_mapping
|
|
169
|
+
|
|
170
|
+
ns_set = ns_set.merge(member_mapping.namespace_set)
|
|
171
|
+
# Recurse into child members
|
|
172
|
+
child_ns = collect_namespaces_recursive(member_mapping, collection.first)
|
|
173
|
+
ns_set = ns_set.merge(child_ns)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
ns_set
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def extract_attributes(graph, mapping)
|
|
181
|
+
attrs = {}
|
|
182
|
+
first_type_uri = mapping.rdf_types.first
|
|
183
|
+
return attrs unless first_type_uri
|
|
184
|
+
|
|
185
|
+
type_uri = RDF::URI(mapping.namespace_set.resolve_compact_iri(first_type_uri))
|
|
186
|
+
matching_subjects = find_subjects_by_type(graph, type_uri)
|
|
187
|
+
|
|
188
|
+
matching_subjects.each do |subject|
|
|
189
|
+
mapping.rdf_predicates.each do |rule|
|
|
190
|
+
stmts = graph.query([subject, RDF::URI(rule.uri), nil])
|
|
191
|
+
next if stmts.empty?
|
|
192
|
+
|
|
193
|
+
values = stmts.map do |s|
|
|
194
|
+
rule.uri_value? ? s.object.to_s : literal_to_ruby(s.object)
|
|
195
|
+
end
|
|
196
|
+
attrs[rule.to] = values.length == 1 ? values.first : values
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
attrs
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def find_subjects_by_type(graph, type_uri)
|
|
204
|
+
graph.query([nil, RDF.type, RDF::URI(type_uri)]).map(&:subject).uniq
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def literal_to_ruby(rdf_object)
|
|
208
|
+
case rdf_object
|
|
209
|
+
when RDF::Literal
|
|
210
|
+
case rdf_object.datatype
|
|
211
|
+
when RDF::XSD.integer then rdf_object.value.to_i
|
|
212
|
+
when RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.float then rdf_object.value.to_f
|
|
213
|
+
when RDF::XSD.boolean then rdf_object.value == "true"
|
|
214
|
+
else rdf_object.value
|
|
215
|
+
end
|
|
216
|
+
else
|
|
217
|
+
rdf_object.to_s
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/turtle"
|
|
4
|
+
require "lutaml/jsonld"
|
|
5
|
+
|
|
6
|
+
require_relative "ext/mapping_ext"
|
|
7
|
+
require_relative "ext/mapping_rule_ext"
|
|
8
|
+
require_relative "ext/member_rule_ext"
|
|
9
|
+
require_relative "ext/turtle_transform_ext"
|
|
10
|
+
require_relative "ext/jsonld_transform_ext"
|
|
11
|
+
|
|
12
|
+
# Update Lutaml::Rdf::Mapping#predicate to pass through `as` option.
|
|
13
|
+
# Update Lutaml::Rdf::Mapping#members to pass through `inline` and `link` options.
|
|
14
|
+
Lutaml::Rdf::Mapping.class_eval do
|
|
15
|
+
def predicate(name, namespace:, to:, lang_tagged: false, as: :literal)
|
|
16
|
+
@rdf_predicates << Lutaml::Rdf::MappingRule.new(
|
|
17
|
+
name,
|
|
18
|
+
namespace: namespace,
|
|
19
|
+
to: to,
|
|
20
|
+
lang_tagged: lang_tagged,
|
|
21
|
+
as: as,
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def members(attr_name, inline: true, link: nil)
|
|
26
|
+
@rdf_members << Lutaml::Rdf::MemberRule.new(attr_name, inline: inline, link: link)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def deep_dup
|
|
30
|
+
self.class.new.tap do |new_mapping|
|
|
31
|
+
new_mapping.namespace_set = @namespace_set
|
|
32
|
+
new_mapping.rdf_subject = @rdf_subject
|
|
33
|
+
new_mapping.rdf_type = @rdf_type
|
|
34
|
+
new_mapping.rdf_types = @rdf_types&.dup
|
|
35
|
+
new_mapping.rdf_predicates = @rdf_predicates.dup
|
|
36
|
+
new_mapping.rdf_members = @rdf_members.dup
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Glossarist
|
|
6
|
+
module Rdf
|
|
7
|
+
class GlossCitation < Lutaml::Model::Serializable
|
|
8
|
+
attribute :source, :string
|
|
9
|
+
attribute :id, :string
|
|
10
|
+
attribute :version, :string
|
|
11
|
+
attribute :link, :string
|
|
12
|
+
attribute :locality, GlossLocality
|
|
13
|
+
|
|
14
|
+
rdf do
|
|
15
|
+
namespace Namespaces::GlossaristNamespace
|
|
16
|
+
|
|
17
|
+
subject { |c| "citation/#{GlossCitation.slug(c)}" }
|
|
18
|
+
|
|
19
|
+
types "gloss:Citation"
|
|
20
|
+
|
|
21
|
+
predicate :citationSource, namespace: Namespaces::GlossaristNamespace, to: :source
|
|
22
|
+
predicate :citationId, namespace: Namespaces::GlossaristNamespace, to: :id
|
|
23
|
+
predicate :citationVersion, namespace: Namespaces::GlossaristNamespace, to: :version
|
|
24
|
+
predicate :citationLink, namespace: Namespaces::GlossaristNamespace, to: :link
|
|
25
|
+
|
|
26
|
+
members :locality, link: "gloss:hasLocality"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.slug(citation)
|
|
30
|
+
slug = [citation.source, citation.id].compact.join("/")
|
|
31
|
+
slug = Digest::MD5.hexdigest(citation.source || "")[0..11] if slug.empty?
|
|
32
|
+
slug
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Glossarist
|
|
6
|
+
module Rdf
|
|
7
|
+
class GlossConcept < Lutaml::Model::Serializable
|
|
8
|
+
include Relationships
|
|
9
|
+
|
|
10
|
+
attribute :identifier, :string
|
|
11
|
+
attribute :status, :string
|
|
12
|
+
attribute :localizations, GlossLocalizedConcept, collection: true
|
|
13
|
+
attribute :sources, GlossConceptSource, collection: true
|
|
14
|
+
attribute :domains, GlossConceptReference, collection: true
|
|
15
|
+
attribute :dates, GlossConceptDate, collection: true
|
|
16
|
+
|
|
17
|
+
rdf do
|
|
18
|
+
namespace Namespaces::GlossaristNamespace,
|
|
19
|
+
Namespaces::SkosNamespace,
|
|
20
|
+
Namespaces::DctermsNamespace,
|
|
21
|
+
Namespaces::SkosxlNamespace,
|
|
22
|
+
Namespaces::IsoThesNamespace,
|
|
23
|
+
Namespaces::RdfNamespace
|
|
24
|
+
|
|
25
|
+
subject { |c| "concept/#{c.identifier}" }
|
|
26
|
+
|
|
27
|
+
types "gloss:Concept", "skos:Concept"
|
|
28
|
+
|
|
29
|
+
predicate :identifier, namespace: Namespaces::GlossaristNamespace, to: :identifier
|
|
30
|
+
predicate :hasStatus, namespace: Namespaces::GlossaristNamespace, to: :status, as: :uri
|
|
31
|
+
|
|
32
|
+
members :localizations,
|
|
33
|
+
link: "gloss:hasLocalization"
|
|
34
|
+
members :sources,
|
|
35
|
+
link: "gloss:hasSource"
|
|
36
|
+
members :domains,
|
|
37
|
+
link: "gloss:hasDomain"
|
|
38
|
+
members :dates,
|
|
39
|
+
link: "gloss:hasDate"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class GlossDocument < Lutaml::Model::Serializable
|
|
44
|
+
attribute :concepts, GlossConcept, collection: true
|
|
45
|
+
|
|
46
|
+
rdf do
|
|
47
|
+
namespace Namespaces::GlossaristNamespace,
|
|
48
|
+
Namespaces::SkosNamespace,
|
|
49
|
+
Namespaces::DctermsNamespace,
|
|
50
|
+
Namespaces::SkosxlNamespace,
|
|
51
|
+
Namespaces::IsoThesNamespace,
|
|
52
|
+
Namespaces::RdfNamespace
|
|
53
|
+
|
|
54
|
+
members :concepts
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Glossarist
|
|
6
|
+
module Rdf
|
|
7
|
+
class GlossConceptDate < Lutaml::Model::Serializable
|
|
8
|
+
attribute :date_value, :string
|
|
9
|
+
attribute :date_type, :string
|
|
10
|
+
attribute :concept_id, :string
|
|
11
|
+
|
|
12
|
+
rdf do
|
|
13
|
+
namespace Namespaces::GlossaristNamespace
|
|
14
|
+
|
|
15
|
+
subject { |d| "concept/#{d.concept_id}/date/#{d.date_type}" }
|
|
16
|
+
|
|
17
|
+
types "gloss:ConceptDate"
|
|
18
|
+
|
|
19
|
+
predicate :dateValue, namespace: Namespaces::GlossaristNamespace, to: :date_value
|
|
20
|
+
predicate :dateType, namespace: Namespaces::GlossaristNamespace, to: :date_type, as: :uri
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Glossarist
|
|
6
|
+
module Rdf
|
|
7
|
+
class GlossConceptReference < Lutaml::Model::Serializable
|
|
8
|
+
attribute :term, :string
|
|
9
|
+
attribute :concept_id, :string
|
|
10
|
+
attribute :source, :string
|
|
11
|
+
attribute :ref_type, :string
|
|
12
|
+
attribute :urn, :string
|
|
13
|
+
attribute :parent_id, :string
|
|
14
|
+
|
|
15
|
+
rdf do
|
|
16
|
+
namespace Namespaces::GlossaristNamespace
|
|
17
|
+
|
|
18
|
+
subject { |r| "concept/#{r.parent_id}/ref/#{r.concept_id || r.urn}" }
|
|
19
|
+
|
|
20
|
+
types "gloss:ConceptReference"
|
|
21
|
+
|
|
22
|
+
predicate :refType, namespace: Namespaces::GlossaristNamespace, to: :ref_type
|
|
23
|
+
predicate :conceptId, namespace: Namespaces::GlossaristNamespace, to: :concept_id
|
|
24
|
+
predicate :sourceUri, namespace: Namespaces::GlossaristNamespace, to: :source
|
|
25
|
+
predicate :urn, namespace: Namespaces::GlossaristNamespace, to: :urn
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Glossarist
|
|
6
|
+
module Rdf
|
|
7
|
+
class GlossConceptSource < Lutaml::Model::Serializable
|
|
8
|
+
attribute :status, :string
|
|
9
|
+
attribute :type, :string
|
|
10
|
+
attribute :modification, :string
|
|
11
|
+
attribute :origin, GlossCitation
|
|
12
|
+
|
|
13
|
+
rdf do
|
|
14
|
+
namespace Namespaces::GlossaristNamespace
|
|
15
|
+
|
|
16
|
+
subject { |s| "source/#{GlossConceptSource.deterministic_id(s)}" }
|
|
17
|
+
|
|
18
|
+
types "gloss:ConceptSource"
|
|
19
|
+
|
|
20
|
+
predicate :sourceStatus, namespace: Namespaces::GlossaristNamespace, to: :status, as: :uri
|
|
21
|
+
predicate :sourceType, namespace: Namespaces::GlossaristNamespace, to: :type, as: :uri
|
|
22
|
+
predicate :modification, namespace: Namespaces::GlossaristNamespace, to: :modification
|
|
23
|
+
|
|
24
|
+
members :origin, link: "gloss:sourceOrigin"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.deterministic_id(source)
|
|
28
|
+
parts = [source.status, source.type, source.modification]
|
|
29
|
+
origin = source.origin
|
|
30
|
+
if origin
|
|
31
|
+
parts << origin.source << origin.id << origin.version << origin.link
|
|
32
|
+
end
|
|
33
|
+
Digest::MD5.hexdigest(parts.compact.join("|"))[0..11]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Glossarist
|
|
6
|
+
module Rdf
|
|
7
|
+
COMMON_DESIGNATION_PREDICATES = lambda { |dsl|
|
|
8
|
+
dsl.predicate :literalForm, namespace: Namespaces::SkosxlNamespace, to: :designation
|
|
9
|
+
dsl.predicate :normativeStatus, namespace: Namespaces::GlossaristNamespace, to: :normative_status, as: :uri
|
|
10
|
+
dsl.predicate :hasTermType, namespace: Namespaces::GlossaristNamespace, to: :term_type, as: :uri
|
|
11
|
+
dsl.predicate :isInternational, namespace: Namespaces::GlossaristNamespace, to: :international
|
|
12
|
+
dsl.predicate :isAbsent, namespace: Namespaces::GlossaristNamespace, to: :absent
|
|
13
|
+
dsl.predicate :geographicalArea, namespace: Namespaces::GlossaristNamespace, to: :language
|
|
14
|
+
dsl.predicate :language, namespace: Namespaces::DctermsNamespace, to: :lang_code
|
|
15
|
+
dsl.predicate :script, namespace: Namespaces::GlossaristNamespace, to: :script
|
|
16
|
+
dsl.predicate :conversionSystem, namespace: Namespaces::GlossaristNamespace, to: :system
|
|
17
|
+
dsl.members :pronunciations, link: "gloss:hasPronunciation"
|
|
18
|
+
dsl.members :sources
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
DESIGNATION_NAMESPACES = [
|
|
22
|
+
Namespaces::GlossaristNamespace,
|
|
23
|
+
Namespaces::SkosxlNamespace,
|
|
24
|
+
Namespaces::SkosNamespace,
|
|
25
|
+
Namespaces::DctermsNamespace,
|
|
26
|
+
Namespaces::IsoThesNamespace,
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
class GlossDesignation < Lutaml::Model::Serializable
|
|
30
|
+
include Relationships
|
|
31
|
+
|
|
32
|
+
attribute :designation, :string
|
|
33
|
+
attribute :normative_status, :string
|
|
34
|
+
attribute :type, :string
|
|
35
|
+
attribute :language, :string
|
|
36
|
+
attribute :script, :string
|
|
37
|
+
attribute :system, :string
|
|
38
|
+
attribute :international, :boolean
|
|
39
|
+
attribute :absent, :boolean
|
|
40
|
+
attribute :term_type, :string
|
|
41
|
+
attribute :concept_id, :string
|
|
42
|
+
attribute :lang_code, :string
|
|
43
|
+
attribute :index, :string
|
|
44
|
+
attribute :pronunciations, GlossPronunciation, collection: true
|
|
45
|
+
attribute :sources, GlossConceptSource, collection: true
|
|
46
|
+
|
|
47
|
+
rdf do
|
|
48
|
+
namespace(*DESIGNATION_NAMESPACES)
|
|
49
|
+
|
|
50
|
+
subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
|
|
51
|
+
|
|
52
|
+
types "gloss:Designation", "skosxl:Label"
|
|
53
|
+
|
|
54
|
+
COMMON_DESIGNATION_PREDICATES.call(self)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class GlossExpression < GlossDesignation
|
|
59
|
+
attribute :prefix, :string
|
|
60
|
+
attribute :usage_info, :string
|
|
61
|
+
attribute :field_of_application, :string
|
|
62
|
+
attribute :grammar_info, GlossGrammarInfo, collection: true
|
|
63
|
+
|
|
64
|
+
rdf do
|
|
65
|
+
namespace(*DESIGNATION_NAMESPACES)
|
|
66
|
+
|
|
67
|
+
subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
|
|
68
|
+
|
|
69
|
+
types "gloss:Expression", "skosxl:Label"
|
|
70
|
+
|
|
71
|
+
COMMON_DESIGNATION_PREDICATES.call(self)
|
|
72
|
+
predicate :prefix, namespace: Namespaces::GlossaristNamespace, to: :prefix
|
|
73
|
+
predicate :usageInfo, namespace: Namespaces::GlossaristNamespace, to: :usage_info
|
|
74
|
+
predicate :fieldOfApplication, namespace: Namespaces::GlossaristNamespace, to: :field_of_application
|
|
75
|
+
members :grammar_info, link: "gloss:hasGrammarInfo"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class GlossAbbreviation < GlossExpression
|
|
80
|
+
attribute :acronym, :boolean
|
|
81
|
+
attribute :initialism, :boolean
|
|
82
|
+
attribute :truncation, :boolean
|
|
83
|
+
|
|
84
|
+
rdf do
|
|
85
|
+
namespace(*DESIGNATION_NAMESPACES)
|
|
86
|
+
|
|
87
|
+
subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
|
|
88
|
+
|
|
89
|
+
types "gloss:Abbreviation", "skosxl:Label"
|
|
90
|
+
|
|
91
|
+
COMMON_DESIGNATION_PREDICATES.call(self)
|
|
92
|
+
predicate :prefix, namespace: Namespaces::GlossaristNamespace, to: :prefix
|
|
93
|
+
predicate :usageInfo, namespace: Namespaces::GlossaristNamespace, to: :usage_info
|
|
94
|
+
predicate :fieldOfApplication, namespace: Namespaces::GlossaristNamespace, to: :field_of_application
|
|
95
|
+
members :grammar_info, link: "gloss:hasGrammarInfo"
|
|
96
|
+
predicate :isAcronym, namespace: Namespaces::GlossaristNamespace, to: :acronym
|
|
97
|
+
predicate :isInitialism, namespace: Namespaces::GlossaristNamespace, to: :initialism
|
|
98
|
+
predicate :isTruncation, namespace: Namespaces::GlossaristNamespace, to: :truncation
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class GlossSymbol < GlossDesignation
|
|
103
|
+
rdf do
|
|
104
|
+
namespace(*DESIGNATION_NAMESPACES)
|
|
105
|
+
|
|
106
|
+
subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
|
|
107
|
+
|
|
108
|
+
types "gloss:Symbol", "skosxl:Label"
|
|
109
|
+
|
|
110
|
+
COMMON_DESIGNATION_PREDICATES.call(self)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class GlossLetterSymbol < GlossSymbol
|
|
115
|
+
attribute :text, :string
|
|
116
|
+
|
|
117
|
+
rdf do
|
|
118
|
+
namespace(*DESIGNATION_NAMESPACES)
|
|
119
|
+
|
|
120
|
+
subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
|
|
121
|
+
|
|
122
|
+
types "gloss:LetterSymbol", "skosxl:Label"
|
|
123
|
+
|
|
124
|
+
COMMON_DESIGNATION_PREDICATES.call(self)
|
|
125
|
+
predicate :text, namespace: Namespaces::GlossaristNamespace, to: :text
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
class GlossGraphicalSymbol < GlossSymbol
|
|
130
|
+
attribute :text, :string
|
|
131
|
+
attribute :image, :string
|
|
132
|
+
|
|
133
|
+
rdf do
|
|
134
|
+
namespace(*DESIGNATION_NAMESPACES)
|
|
135
|
+
|
|
136
|
+
subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
|
|
137
|
+
|
|
138
|
+
types "gloss:GraphicalSymbol", "skosxl:Label"
|
|
139
|
+
|
|
140
|
+
COMMON_DESIGNATION_PREDICATES.call(self)
|
|
141
|
+
predicate :text, namespace: Namespaces::GlossaristNamespace, to: :text
|
|
142
|
+
predicate :image, namespace: Namespaces::GlossaristNamespace, to: :image
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|