ttl2html 3.0.0 → 3.1.1
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/lib/ttl2html/template.rb +14 -2
- data/lib/ttl2html/version.rb +1 -1
- data/lib/ttl2html.rb +134 -24
- data/locales/en.yml +1 -0
- data/locales/ja.yml +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5d181672a5b0aa4cd6f7f1599fb20b6102c5232b3f774069038023bfc65d05a0
|
|
4
|
+
data.tar.gz: 313970beef022f77e7f4d5bac9da410adcc6203a6dd7d073d6ab2b49a516ebae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fdd4152bfc2ab82d97bed51c63dd8814e89a40b31d2e84ca2a64406dcfd4be373a393ccf8b2ebd477adb8e1f4df844f355872537232e7ec9357063ff2c123760
|
|
7
|
+
data.tar.gz: 7821d98735d0fadf33671017573accb9d765e2e2bd571c9fb66435251a056cedab6e05ec20b760c940cc2f1daa16bbdde11496cadcf4045fa9016344904e36db
|
data/lib/ttl2html/template.rb
CHANGED
|
@@ -98,12 +98,24 @@ module TTL2HTML
|
|
|
98
98
|
end
|
|
99
99
|
#p nodes
|
|
100
100
|
end
|
|
101
|
+
example = data[property]["http://www.w3.org/2004/02/skos/core#example"].first if data[property]["http://www.w3.org/2004/02/skos/core#example"]
|
|
102
|
+
if example.respond_to?(:datatype) and example.datatype?
|
|
103
|
+
datatype = example.datatype.pname or example.datatype.to_s
|
|
104
|
+
example = example.to_s + "<span class=\"datatype\">^^" + example.datatype.pname + "</span>"
|
|
105
|
+
end
|
|
106
|
+
descriptions = [ get_language_literal(data[property]["http://www.w3.org/ns/shacl#description"]) ]
|
|
107
|
+
if data[property]["http://www.w3.org/ns/shacl#datatype"]
|
|
108
|
+
datatypes = data[property]["http://www.w3.org/ns/shacl#datatype"].map do |datatype|
|
|
109
|
+
datatype.to_s.sub(%r{\Ahttp://www\.w3\.org/2001/XMLSchema#}, 'xsd:')
|
|
110
|
+
end.join(", ")
|
|
111
|
+
descriptions << t('shape-table.datatype') + datatypes
|
|
112
|
+
end
|
|
101
113
|
{
|
|
102
114
|
path: path,
|
|
103
115
|
shorten_path: shorten_path,
|
|
104
116
|
name: get_language_literal(data[property]["http://www.w3.org/ns/shacl#name"]),
|
|
105
|
-
example:
|
|
106
|
-
description:
|
|
117
|
+
example: example,
|
|
118
|
+
description: descriptions.compact.join("<br>"),
|
|
107
119
|
required: data[property]["http://www.w3.org/ns/shacl#minCount"] ? data[property]["http://www.w3.org/ns/shacl#minCount"].first.to_i > 0 : false,
|
|
108
120
|
repeatable: repeatable,
|
|
109
121
|
nodeKind: data[property]["http://www.w3.org/ns/shacl#nodeKind"] ? data[property]["http://www.w3.org/ns/shacl#nodeKind"].first : nil,
|
data/lib/ttl2html/version.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
TTL2HTML::VERSION = "3.
|
|
1
|
+
TTL2HTML::VERSION = "3.1.1"
|
data/lib/ttl2html.rb
CHANGED
|
@@ -72,9 +72,31 @@ module TTL2HTML
|
|
|
72
72
|
$stderr.puts "#{count} triples. #{subjects.size} subjects."
|
|
73
73
|
@data
|
|
74
74
|
end
|
|
75
|
-
|
|
75
|
+
QB_ORDER_URI = "http://purl.org/linked-data/cube#order"
|
|
76
|
+
SCHEMA_POSITION_URI = "http://schema.org/position"
|
|
77
|
+
SHACL_ORDER_URI = "http://www.w3.org/ns/shacl#order"
|
|
78
|
+
def sort_key_for_resource(resource, depth = 1)
|
|
79
|
+
qb_order = Float::INFINITY
|
|
80
|
+
schema_position = Float::INFINITY
|
|
81
|
+
shacl_order = Float::INFINITY
|
|
82
|
+
if @data[resource.to_s]
|
|
83
|
+
qb_order = @data[resource.to_s][QB_ORDER_URI].first.to_i if @data[resource.to_s][QB_ORDER_URI]
|
|
84
|
+
schema_position = @data[resource.to_s][SCHEMA_POSITION_URI].first.to_i if @data[resource.to_s][SCHEMA_POSITION_URI]
|
|
85
|
+
shacl_order = @data[resource.to_s][SHACL_ORDER_URI].first.to_i if @data[resource.to_s][SHACL_ORDER_URI]
|
|
86
|
+
end
|
|
87
|
+
if resource.to_s =~ /^_:/ and depth < 5
|
|
88
|
+
[ schema_position, qb_order, shacl_order,
|
|
89
|
+
format_turtle(resource, depth + 1, true)
|
|
90
|
+
]
|
|
91
|
+
else
|
|
92
|
+
[ schema_position, qb_order, shacl_order, resource.to_s]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
def format_turtle(subject, depth = 1, force = false)
|
|
76
96
|
turtle = RDF::Turtle::Writer.new
|
|
77
97
|
result = ""
|
|
98
|
+
#p [:format_turtle, subject, depth, force]
|
|
99
|
+
return result if !force && @cache[:output_turtle_files].include?(subject)
|
|
78
100
|
if subject =~ /^_:/
|
|
79
101
|
result << "[\n#{" "*depth}"
|
|
80
102
|
else
|
|
@@ -85,21 +107,10 @@ module TTL2HTML
|
|
|
85
107
|
#p [subject, predicate, @data[subject.to_s][predicate]]
|
|
86
108
|
str << @data[subject.to_s][predicate].sort_by do |object|
|
|
87
109
|
#p [subject, predicate, object, depth]
|
|
88
|
-
|
|
89
|
-
qb_order = "http://purl.org/linked-data/cube#order"
|
|
90
|
-
schema_position = "http://schema.org/position"
|
|
91
|
-
shacl_order = "http://www.w3.org/ns/shacl#order"
|
|
92
|
-
[ @data[object.to_s][schema_position] ? @data[object.to_s][schema_position].first.to_i : Float::INFINITY,
|
|
93
|
-
@data[object.to_s][qb_order] ? @data[object.to_s][qb_order].first.to_i : Float::INFINITY,
|
|
94
|
-
@data[object.to_s][shacl_order] ? @data[object.to_s][shacl_order].first.to_i : Float::INFINITY,
|
|
95
|
-
format_turtle(object, depth + 1)
|
|
96
|
-
]
|
|
97
|
-
else
|
|
98
|
-
[Float::INFINITY, Float::INFINITY, Float::INFINITY, object.to_s]
|
|
99
|
-
end
|
|
110
|
+
sort_key_for_resource(object, depth)
|
|
100
111
|
end.map do |object|
|
|
101
112
|
if /^_:/ =~ object.to_s # blank node:
|
|
102
|
-
format_turtle(object, depth + 1)
|
|
113
|
+
format_turtle(object, depth + 1, force)
|
|
103
114
|
elsif RDF::URI::IRI =~ object.to_s
|
|
104
115
|
turtle.format_uri(RDF::URI.new object)
|
|
105
116
|
elsif object.respond_to?(:first) and object.first.kind_of?(Symbol)
|
|
@@ -110,22 +121,117 @@ module TTL2HTML
|
|
|
110
121
|
end.join(", ")
|
|
111
122
|
str
|
|
112
123
|
end.join(";\n#{" "*depth}")
|
|
113
|
-
result << "
|
|
124
|
+
result << "." if not subject =~ /^_:/
|
|
114
125
|
result << "\n"
|
|
115
126
|
result << "#{" "*(depth-1)}]" if subject =~ /^_:/
|
|
127
|
+
@cache[:output_turtle_files] << subject unless force
|
|
116
128
|
result
|
|
117
129
|
end
|
|
118
130
|
def format_turtle_inverse(object)
|
|
119
|
-
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
131
|
+
triples = collect_inverse_triples(object)
|
|
132
|
+
return "" if triples.empty?
|
|
133
|
+
by_subject = build_subject_index(triples)
|
|
134
|
+
ref_count = build_object_ref_count(triples)
|
|
135
|
+
roots = find_inverse_roots(by_subject)
|
|
136
|
+
roots.map do |root|
|
|
137
|
+
"#{format_inverse_subject(root, by_subject, ref_count, Set.new, 1)}.\n"
|
|
138
|
+
end.join
|
|
139
|
+
end
|
|
140
|
+
def collect_inverse_triples(object, triples = Set.new, visited = Set.new)
|
|
141
|
+
return triples if object.to_s.start_with?("_:")
|
|
142
|
+
return triples unless object.to_s.start_with?(@config[:base_uri].to_s)
|
|
143
|
+
return triples unless @data_inverse.key?(object.to_s)
|
|
144
|
+
return triples if visited.include?(object.to_s)
|
|
145
|
+
visited << object.to_s
|
|
146
|
+
@data_inverse[object.to_s].each do |predicate, subjects|
|
|
147
|
+
subjects.each do |subject|
|
|
148
|
+
triples << [subject.to_s, predicate.to_s, object.to_s]
|
|
149
|
+
collect_inverse_triples_for_bnode(subject.to_s, triples, visited) if subject.to_s.start_with?("_:")
|
|
126
150
|
end
|
|
127
151
|
end
|
|
128
|
-
|
|
152
|
+
triples
|
|
153
|
+
end
|
|
154
|
+
def collect_inverse_triples_for_bnode(node, triples, visited)
|
|
155
|
+
return triples unless @data_inverse.key?(node)
|
|
156
|
+
return triples if visited.include?(node)
|
|
157
|
+
visited << node
|
|
158
|
+
@data_inverse[node].each do |predicate, subjects|
|
|
159
|
+
subjects.each do |subject|
|
|
160
|
+
triples << [subject.to_s, predicate.to_s, node]
|
|
161
|
+
collect_inverse_triples_for_bnode(subject.to_s, triples, visited) if subject.to_s.start_with?("_:")
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
triples
|
|
165
|
+
end
|
|
166
|
+
def build_subject_index(triples)
|
|
167
|
+
by_subject = Hash.new { |h, k| h[k] = Hash.new { |hh, kk| hh[kk] = [] } }
|
|
168
|
+
triples.each do |subject, predicate, object|
|
|
169
|
+
by_subject[subject][predicate] << object
|
|
170
|
+
end
|
|
171
|
+
by_subject.each_value do |predicates|
|
|
172
|
+
predicates.each_value(&:uniq!)
|
|
173
|
+
end
|
|
174
|
+
by_subject
|
|
175
|
+
end
|
|
176
|
+
def build_object_ref_count(triples)
|
|
177
|
+
count = Hash.new(0)
|
|
178
|
+
triples.each do |_subject, _predicate, object|
|
|
179
|
+
count[object] += 1 if object.to_s.start_with?("_:")
|
|
180
|
+
end
|
|
181
|
+
count
|
|
182
|
+
end
|
|
183
|
+
def find_inverse_roots(by_subject)
|
|
184
|
+
all_subjects = by_subject.keys
|
|
185
|
+
all_objects = by_subject.values.flat_map { |preds| preds.values.flatten }.uniq
|
|
186
|
+
all_subjects.reject do |subject|
|
|
187
|
+
subject.start_with?("_:") || all_objects.include?(subject)
|
|
188
|
+
end.sort
|
|
189
|
+
end
|
|
190
|
+
def format_inverse_subject(subject, by_subject, ref_count, visited, depth = 1)
|
|
191
|
+
props = by_subject[subject]
|
|
192
|
+
return format_node(subject) if props.nil? || props.empty?
|
|
193
|
+
indent = " " * (depth - 1)
|
|
194
|
+
inner = " " * depth
|
|
195
|
+
if subject.start_with?("_:")
|
|
196
|
+
return "[]" if visited.include?(subject)
|
|
197
|
+
visited = visited.dup
|
|
198
|
+
visited << subject
|
|
199
|
+
head = "[\n#{inner}"
|
|
200
|
+
tail = "\n#{indent}]"
|
|
201
|
+
else
|
|
202
|
+
head = "<#{subject}> "
|
|
203
|
+
tail = ""
|
|
204
|
+
end
|
|
205
|
+
body = props.keys.sort.map do |predicate|
|
|
206
|
+
objects = props[predicate].sort.map do |object|
|
|
207
|
+
format_inverse_object(object, by_subject, ref_count, visited, depth + 1)
|
|
208
|
+
end.join(", ")
|
|
209
|
+
"<#{predicate}> #{objects}"
|
|
210
|
+
end.join(";\n#{inner}")
|
|
211
|
+
head + body + tail
|
|
212
|
+
end
|
|
213
|
+
def format_inverse_object(object, by_subject, ref_count, visited, depth = 1)
|
|
214
|
+
if object.to_s.start_with?("_:") && by_subject.key?(object.to_s)
|
|
215
|
+
if ref_count[object.to_s] <= 1
|
|
216
|
+
format_inverse_subject(object.to_s, by_subject, ref_count, visited, depth)
|
|
217
|
+
else
|
|
218
|
+
object.to_s
|
|
219
|
+
end
|
|
220
|
+
else
|
|
221
|
+
format_node(object)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
def format_node(value)
|
|
225
|
+
turtle = RDF::Turtle::Writer.new
|
|
226
|
+
if value.to_s.start_with?("_:")
|
|
227
|
+
value.to_s
|
|
228
|
+
elsif RDF::URI::IRI =~ value.to_s
|
|
229
|
+
"<#{value}>"
|
|
230
|
+
elsif value.respond_to?(:first) && value.first.kind_of?(Symbol)
|
|
231
|
+
turtle.format_literal(RDF::Literal.new(value[1], language: value[0]))
|
|
232
|
+
else
|
|
233
|
+
turtle.format_literal(value)
|
|
234
|
+
end
|
|
129
235
|
end
|
|
130
236
|
|
|
131
237
|
def each_data(label = :each_data)
|
|
@@ -218,7 +324,9 @@ module TTL2HTML
|
|
|
218
324
|
param[:versions] = versions
|
|
219
325
|
param[:toplevel] = toplevel
|
|
220
326
|
param[:description] = template.to_html_raw("description.html", {}) if template.find_template_path("description.html")
|
|
221
|
-
subjects.
|
|
327
|
+
subjects.sort_by do |subject|
|
|
328
|
+
sort_key_for_resource(subject)
|
|
329
|
+
end.each do |subject|
|
|
222
330
|
objects = []
|
|
223
331
|
if @config.has_key? :top_additional_property
|
|
224
332
|
@config[:top_additional_property].each do |property|
|
|
@@ -521,6 +629,8 @@ module TTL2HTML
|
|
|
521
629
|
end
|
|
522
630
|
dir = File.dirname(file)
|
|
523
631
|
FileUtils.mkdir_p(dir) if not File.exist?(dir)
|
|
632
|
+
@cache ||= {}
|
|
633
|
+
@cache[:output_turtle_files] = Set.new
|
|
524
634
|
str = format_turtle(uri)
|
|
525
635
|
str << format_turtle_inverse(uri)
|
|
526
636
|
open(file, "w") do |io|
|
data/locales/en.yml
CHANGED
|
@@ -45,6 +45,7 @@ en:
|
|
|
45
45
|
non-repeatable: "Non repeatable"
|
|
46
46
|
blank-node-structure: "The structural contents of a blank node are as follows:"
|
|
47
47
|
blank-node-or-structure: "The structural contents of a blank node are either of the followings:"
|
|
48
|
+
datatype: "Datatype: "
|
|
48
49
|
triples:
|
|
49
50
|
inverse_refered: "Referred to as '%{property}' from:"
|
|
50
51
|
blank_node: "Blank node"
|
data/locales/ja.yml
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ttl2html
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Masao Takaku
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-04-
|
|
10
|
+
date: 2026-04-29 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: nokogiri
|
|
@@ -210,7 +210,9 @@ files:
|
|
|
210
210
|
homepage: https://github.com/masao/ttl2html
|
|
211
211
|
licenses:
|
|
212
212
|
- MIT
|
|
213
|
-
metadata:
|
|
213
|
+
metadata:
|
|
214
|
+
bug_tracker_uri: https://github.com/masao/ttl2html/issues
|
|
215
|
+
documentation_uri: https://ttl2html-doc.readthedocs.io/
|
|
214
216
|
rdoc_options: []
|
|
215
217
|
require_paths:
|
|
216
218
|
- lib
|
|
@@ -225,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
225
227
|
- !ruby/object:Gem::Version
|
|
226
228
|
version: '0'
|
|
227
229
|
requirements: []
|
|
228
|
-
rubygems_version: 4.0.
|
|
230
|
+
rubygems_version: 4.0.10
|
|
229
231
|
specification_version: 4
|
|
230
232
|
summary: ttl2html
|
|
231
233
|
test_files: []
|