yowl 0.4.pre
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.
- data/CHANGES +15 -0
- data/INSTALL-MACOSX.md +107 -0
- data/README.md +92 -0
- data/Rakefile +76 -0
- data/bin/yowl +14 -0
- data/examples/introduction.html +5 -0
- data/lib/yowl/association.rb +66 -0
- data/lib/yowl/class.rb +296 -0
- data/lib/yowl/generator.rb +96 -0
- data/lib/yowl/import.rb +62 -0
- data/lib/yowl/individual.rb +398 -0
- data/lib/yowl/individual_association.rb +80 -0
- data/lib/yowl/ontology.rb +197 -0
- data/lib/yowl/options.rb +116 -0
- data/lib/yowl/optionsparser.rb +75 -0
- data/lib/yowl/person.rb +26 -0
- data/lib/yowl/property.rb +190 -0
- data/lib/yowl/repository.rb +100 -0
- data/lib/yowl/schema.rb +519 -0
- data/lib/yowl/template/css/jquery.ui.all.css +11 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/lib/yowl/template/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/yowl/template/css/smoothness/jquery-ui-1.8.23.custom.css +563 -0
- data/lib/yowl/template/css/yowl.css +414 -0
- data/lib/yowl/template/import-diagram.erb +29 -0
- data/lib/yowl/template/index.erb +56 -0
- data/lib/yowl/template/js/jquery-1.7.2.min.js +4 -0
- data/lib/yowl/template/js/jquery-ui-1.8.23.custom.min.js +125 -0
- data/lib/yowl/template/js/jquery.ui.accordion.js +611 -0
- data/lib/yowl/template/js/yowl.js +72 -0
- data/lib/yowl/template/ontology.erb +598 -0
- data/lib/yowl/template/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-icons_222222_256x240.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-icons_454545_256x240.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-icons_888888_256x240.png +0 -0
- data/lib/yowl/template/themes/base/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/yowl/template/themes/base/jquery.ui.accordion.css +19 -0
- data/lib/yowl/template/themes/base/jquery.ui.all.css +11 -0
- data/lib/yowl/template/themes/base/jquery.ui.autocomplete.css +53 -0
- data/lib/yowl/template/themes/base/jquery.ui.base.css +11 -0
- data/lib/yowl/template/themes/base/jquery.ui.button.css +38 -0
- data/lib/yowl/template/themes/base/jquery.ui.core.css +38 -0
- data/lib/yowl/template/themes/base/jquery.ui.datepicker.css +66 -0
- data/lib/yowl/template/themes/base/jquery.ui.dialog.css +21 -0
- data/lib/yowl/template/themes/base/jquery.ui.progressbar.css +11 -0
- data/lib/yowl/template/themes/base/jquery.ui.resizable.css +20 -0
- data/lib/yowl/template/themes/base/jquery.ui.selectable.css +10 -0
- data/lib/yowl/template/themes/base/jquery.ui.slider.css +24 -0
- data/lib/yowl/template/themes/base/jquery.ui.tabs.css +18 -0
- data/lib/yowl/template/themes/base/jquery.ui.theme.css +247 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/lib/yowl/template/themes/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/yowl/template/themes/smoothness/jquery-ui-1.8.23.custom.css +563 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.accordion.css +19 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.all.css +11 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.autocomplete.css +53 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.base.css +11 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.button.css +38 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.core.css +38 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.datepicker.css +66 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.dialog.css +21 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.progressbar.css +11 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.resizable.css +20 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.selectable.css +10 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.slider.css +24 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.tabs.css +18 -0
- data/lib/yowl/template/themes/smoothness/jquery.ui.theme.css +249 -0
- data/lib/yowl/util.rb +221 -0
- data/lib/yowl/version.rb +3 -0
- data/lib/yowl.rb +42 -0
- data/test/input/base-with-comments.ttl +163 -0
- data/test/input/base.ttl +221 -0
- data/test/input/empty.ttl +8 -0
- data/test/input/example.ttl +73 -0
- data/test/test_example_ttl.rb +62 -0
- data/test/test_yowl.rb +4 -0
- data/test/testcases.md +24 -0
- metadata +311 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module YOWL
|
|
2
|
+
|
|
3
|
+
class Generator
|
|
4
|
+
|
|
5
|
+
def initialize(repository, options)
|
|
6
|
+
@options = options
|
|
7
|
+
@repository = repository
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
def generateOntologyHtmlFiles()
|
|
12
|
+
@repository.schemas.values.each() do |schema|
|
|
13
|
+
generateOntologyHtmlFile(schema)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
def generateOntologyHtmlFile(schema)
|
|
19
|
+
if @options.verbose
|
|
20
|
+
puts "Generating documentation for ontology #{schema.ontology.title}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
introduction = @introduction
|
|
24
|
+
repository = @repository
|
|
25
|
+
|
|
26
|
+
b = binding
|
|
27
|
+
|
|
28
|
+
begin
|
|
29
|
+
Dir.mkdir(@options.output_dir)
|
|
30
|
+
rescue Errno::EEXIST
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
ontologyFile = File.join(@options.output_dir, "#{schema.name}.html")
|
|
34
|
+
if @options.verbose
|
|
35
|
+
puts "Generating #{ontologyFile}"
|
|
36
|
+
end
|
|
37
|
+
File.open(ontologyFile, 'w') do |file|
|
|
38
|
+
file.write(@options.templates['ontology'].result(b))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
def generateHtmlFile(templateName_)
|
|
44
|
+
|
|
45
|
+
template = @options.templates[templateName_]
|
|
46
|
+
|
|
47
|
+
if template.nil?
|
|
48
|
+
puts "Not generating #{templateName_}.html since #{templateName_} template could not be found."
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
fileName = File.join(@options.output_dir, "#{templateName_}.html")
|
|
52
|
+
if @options.verbose
|
|
53
|
+
puts "Generating #{fileName}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
repository = @repository
|
|
57
|
+
schemas = @repository.schemas.values
|
|
58
|
+
ontologies = @repository.ontologies()
|
|
59
|
+
|
|
60
|
+
b = binding
|
|
61
|
+
|
|
62
|
+
File.open(fileName, 'w') do |file|
|
|
63
|
+
file.write(template.result(b))
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
def copyTemplateDir(src_, tgt_)
|
|
69
|
+
if Dir[src_] == []
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
puts "Copying #{src_} -> #{tgt_}"
|
|
73
|
+
FileUtils.cp_r src_, tgt_
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
def copyTemplates()
|
|
78
|
+
|
|
79
|
+
@options.template_dirs.each do |template_dir|
|
|
80
|
+
copyTemplateDir("#{template_dir}/js", "#{@options.output_dir}")
|
|
81
|
+
copyTemplateDir("#{template_dir}/css", "#{@options.output_dir}")
|
|
82
|
+
copyTemplateDir("#{template_dir}/themes", "#{@options.output_dir}")
|
|
83
|
+
copyTemplateDir("#{template_dir}/img", "#{@options.output_dir}")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
public
|
|
88
|
+
def run()
|
|
89
|
+
copyTemplates()
|
|
90
|
+
generateHtmlFile('index')
|
|
91
|
+
generateHtmlFile('introduction')
|
|
92
|
+
generateHtmlFile('import-diagram')
|
|
93
|
+
generateOntologyHtmlFiles()
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/yowl/import.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'yowl'
|
|
2
|
+
|
|
3
|
+
module YOWL
|
|
4
|
+
|
|
5
|
+
class Import < YOWL::LabelledDocObject
|
|
6
|
+
|
|
7
|
+
attr_reader :importedSchema
|
|
8
|
+
attr_reader :importedOntology
|
|
9
|
+
|
|
10
|
+
def initialize(resource_, schema_)
|
|
11
|
+
super(resource_, schema_)
|
|
12
|
+
|
|
13
|
+
@importedSchema = schema_.repository.getSchemaForImport(self)
|
|
14
|
+
@importedOntology = @importedSchema ? @importedSchema.ontology : nil
|
|
15
|
+
|
|
16
|
+
if @importedSchema.nil?
|
|
17
|
+
puts "WARNING: #{@schema.fileName}: Created Import #{uri} but did not find schema for it "
|
|
18
|
+
end
|
|
19
|
+
if @importedOntology.nil?
|
|
20
|
+
puts "WARNING: #{@schema.fileName}: Created Import #{uri} but did not find ontology for it "
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def name
|
|
25
|
+
if @importedSchema
|
|
26
|
+
return @importedSchema.name
|
|
27
|
+
end
|
|
28
|
+
prefix, ns = @schema.prefixForNamespace(uri)
|
|
29
|
+
if prefix
|
|
30
|
+
return prefix
|
|
31
|
+
end
|
|
32
|
+
return short_name
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def resourceNameHtml
|
|
36
|
+
return "#{@name}.html"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def imports
|
|
40
|
+
return @importedOntology ? @importedOntology.imports : []
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def isExternal?
|
|
44
|
+
return (@importedSchema.nil? and @importedOntology.nil?)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# See YOWL::Individual::classWithURI(uri)
|
|
49
|
+
#
|
|
50
|
+
def classWithURI(uri_)
|
|
51
|
+
if isExternal?
|
|
52
|
+
return nil
|
|
53
|
+
end
|
|
54
|
+
if @importedSchema
|
|
55
|
+
return @importedSchema.classWithURI(uri_)
|
|
56
|
+
end
|
|
57
|
+
puts "WARNING: Cannot check whether class #{uri_.to_s} exists in imported ontology #{uri} as this ontology is not loaded"
|
|
58
|
+
return nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
module YOWL
|
|
2
|
+
#
|
|
3
|
+
# Represents an Individual defined in the schema
|
|
4
|
+
#
|
|
5
|
+
class Individual < YOWL::LabelledDocObject
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
def initialize(resource, schema)
|
|
9
|
+
super(resource, schema)
|
|
10
|
+
if schema.options.verbose
|
|
11
|
+
puts "Created Individual #{short_name}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
public
|
|
16
|
+
def Individual.withUri(resource, schema)
|
|
17
|
+
if resource.anonymous?
|
|
18
|
+
warn "WARNING: Ignoring Individual with uri #{resource.to_s}"
|
|
19
|
+
return
|
|
20
|
+
end
|
|
21
|
+
individual = schema.individuals[resource.to_s]
|
|
22
|
+
if individual
|
|
23
|
+
return individual
|
|
24
|
+
end
|
|
25
|
+
individual = Individual.new(resource, schema)
|
|
26
|
+
schema.individuals[resource.to_s] = individual
|
|
27
|
+
return individual
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
public
|
|
31
|
+
#
|
|
32
|
+
# This label is a bit different than the one in the base class as this one
|
|
33
|
+
# gets its prefix stripped, if there is one.
|
|
34
|
+
#
|
|
35
|
+
def label
|
|
36
|
+
@label ||= init_label
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
def init_label
|
|
41
|
+
label = get_literal(YOWL::Namespaces::RDFS.label)
|
|
42
|
+
if label
|
|
43
|
+
return label
|
|
44
|
+
end
|
|
45
|
+
label = short_name
|
|
46
|
+
label = label.sub(/(.*)\s*:/, "")
|
|
47
|
+
label = label.gsub("_", " ")
|
|
48
|
+
|
|
49
|
+
label.sub!(/^r29-/, "") # TODO: Make this configurable via setting in ontology
|
|
50
|
+
|
|
51
|
+
classes.each do |klass|
|
|
52
|
+
className = klass.short_name
|
|
53
|
+
label.chomp!("-#{className}")
|
|
54
|
+
className.sub!(/.*:/, '')
|
|
55
|
+
label.chomp!("-#{className}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
return label
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
def gvLabel
|
|
63
|
+
tmp = label.gsub(", ", ",\n")
|
|
64
|
+
return prefix ? "#{tmp}\n(#{prefix})" : tmp
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
public
|
|
68
|
+
#
|
|
69
|
+
# The prefix to be used for the URI of this Individual, if defined, nil if it isn't
|
|
70
|
+
#
|
|
71
|
+
def prefix
|
|
72
|
+
@prefix ||= init_prefix
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
def init_prefix
|
|
77
|
+
name = short_name
|
|
78
|
+
return name.include?(':') ? short_name.sub(/:\s*(.*)/, "") : nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
public
|
|
82
|
+
def types
|
|
83
|
+
if not defined?(@types)
|
|
84
|
+
init_types
|
|
85
|
+
end
|
|
86
|
+
return @types
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
def init_types
|
|
91
|
+
@types = []
|
|
92
|
+
@schema.model.query(
|
|
93
|
+
RDF::Query::Pattern.new(@resource, RDF.type)
|
|
94
|
+
) do |statement|
|
|
95
|
+
if statement.object == YOWL::Namespaces::OWL.NamedIndividual
|
|
96
|
+
next
|
|
97
|
+
end
|
|
98
|
+
@types << statement.object
|
|
99
|
+
if @schema.options.verbose
|
|
100
|
+
puts "Found Type #{statement.object.to_s} for Individual #{label}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
public
|
|
106
|
+
def classes
|
|
107
|
+
if not defined?(@classes)
|
|
108
|
+
init_classes
|
|
109
|
+
end
|
|
110
|
+
return @classes
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private
|
|
114
|
+
def init_classes
|
|
115
|
+
@classes = []
|
|
116
|
+
types.each do |type|
|
|
117
|
+
klass = @schema.classWithURI(type)
|
|
118
|
+
if klass
|
|
119
|
+
@classes << klass
|
|
120
|
+
if @schema.options.verbose
|
|
121
|
+
puts "Found Class #{klass.short_name} for Individual #{label}"
|
|
122
|
+
end
|
|
123
|
+
else
|
|
124
|
+
puts "WARNING: Could not find Class definition for URI #{type.to_s}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
public
|
|
130
|
+
def isSkosConceptScheme?
|
|
131
|
+
conceptSchemeClassURI = YOWL::Namespaces::SKOS.ConceptScheme.to_s
|
|
132
|
+
types.each do |type|
|
|
133
|
+
#puts "isSkosConceptScheme #{type.to_s} #{conceptSchemeClassURI}"
|
|
134
|
+
if type.to_s == conceptSchemeClassURI
|
|
135
|
+
return true
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
return false
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
public
|
|
142
|
+
def isSkosConcept?
|
|
143
|
+
puts "isSkosConcept #{@resource}"
|
|
144
|
+
inScheme = get_literal(YOWL::Namespaces::SKOS.inScheme)
|
|
145
|
+
if not inScheme.nil?
|
|
146
|
+
return true
|
|
147
|
+
end
|
|
148
|
+
topConceptOf = get_literal(YOWL::Namespaces::SKOS.topConceptOf)
|
|
149
|
+
if not topConceptOf.nil?
|
|
150
|
+
return true
|
|
151
|
+
end
|
|
152
|
+
return false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
public
|
|
156
|
+
def isSkosConceptInScheme?(conceptScheme_)
|
|
157
|
+
inScheme = get_literal(YOWL::Namespaces::SKOS.inScheme)
|
|
158
|
+
if inScheme and inScheme.uri == conceptScheme_.uri
|
|
159
|
+
puts "isSkosConceptInScheme #{@resource}: #{inScheme.uri}"
|
|
160
|
+
return true
|
|
161
|
+
end
|
|
162
|
+
return false
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
public
|
|
166
|
+
#
|
|
167
|
+
# Return a collection of Associations representing ObjectProperties
|
|
168
|
+
# where the current class is one of the Domain classes.
|
|
169
|
+
#
|
|
170
|
+
def associatedIndividuals
|
|
171
|
+
if not defined?(@associatedIndividuals)
|
|
172
|
+
init_associatedIndividuals
|
|
173
|
+
end
|
|
174
|
+
return @associatedIndividuals
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private
|
|
178
|
+
def init_associatedIndividuals()
|
|
179
|
+
@associatedIndividuals = Hash.new
|
|
180
|
+
|
|
181
|
+
if @schema.options.verbose
|
|
182
|
+
puts "Searching for associations of Individual #{short_name}"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
sparql = <<sparql
|
|
186
|
+
SELECT DISTINCT ?individual WHERE {
|
|
187
|
+
{
|
|
188
|
+
?individual a owl:NamedIndividual .
|
|
189
|
+
?individual ?predicateA <#{uri}> .
|
|
190
|
+
} UNION {
|
|
191
|
+
<#{uri}>
|
|
192
|
+
a owl:NamedIndividual ;
|
|
193
|
+
?predicateB ?individual ;
|
|
194
|
+
.
|
|
195
|
+
?individual a owl:NamedIndividual .
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
sparql
|
|
199
|
+
#if @schema.options.verbose
|
|
200
|
+
# puts " - SPARQL: #{sparql}"
|
|
201
|
+
#end
|
|
202
|
+
solutions = SPARQL.execute(sparql, @schema.model, { :prefixes => @schema.prefixes })
|
|
203
|
+
if @schema.options.verbose
|
|
204
|
+
puts " - Found #{solutions.count} associated Individuals"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
solutions.each do |solution|
|
|
208
|
+
individual = Individual.withUri(solution[:individual], @schema)
|
|
209
|
+
if @schema.options.verbose
|
|
210
|
+
puts " - Found Individual #{individual.short_name}"
|
|
211
|
+
end
|
|
212
|
+
@associatedIndividuals[individual.uri] = individual
|
|
213
|
+
end
|
|
214
|
+
return @associatedIndividuals
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
#
|
|
218
|
+
# Return a collection of IndividualAssociations representing ObjectProperties
|
|
219
|
+
# where the current Individual is the subject/resource.
|
|
220
|
+
#
|
|
221
|
+
def outboundAssociations()
|
|
222
|
+
if defined?(@outboundAssociations)
|
|
223
|
+
return @outboundAssociations
|
|
224
|
+
end
|
|
225
|
+
@outboundAssociations = Set.new
|
|
226
|
+
|
|
227
|
+
if @schema.options.verbose
|
|
228
|
+
puts "Searching for associations of individual #{short_name}"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
sparql = <<sparql
|
|
232
|
+
SELECT DISTINCT ?individual ?predicate WHERE {
|
|
233
|
+
<#{uri}>
|
|
234
|
+
a owl:NamedIndividual ;
|
|
235
|
+
?predicate ?individual
|
|
236
|
+
.
|
|
237
|
+
?individual a owl:NamedIndividual .
|
|
238
|
+
}
|
|
239
|
+
sparql
|
|
240
|
+
|
|
241
|
+
#if @schema.options.verbose
|
|
242
|
+
# puts " - SPARQL: #{sparql}"
|
|
243
|
+
#end
|
|
244
|
+
solutions = SPARQL.execute(sparql, @schema.model, { :prefixes => @schema.prefixes })
|
|
245
|
+
if @schema.options.verbose
|
|
246
|
+
puts " - Found #{solutions.count} associated 'outbound' Individual Associations"
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
solutions.each do |solution|
|
|
250
|
+
individual = Individual.withUri(solution[:individual], @schema)
|
|
251
|
+
predicate = solution[:predicate]
|
|
252
|
+
@outboundAssociations << IndividualAssociation.new(predicate, @schema, self, individual)
|
|
253
|
+
end
|
|
254
|
+
if @schema.options.verbose
|
|
255
|
+
puts " - Returning #{@outboundAssociations.size} associations for Individual #{short_name}"
|
|
256
|
+
end
|
|
257
|
+
return @outboundAssociations
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
#
|
|
261
|
+
# Return a collection of IndividualAssociations representing ObjectProperties
|
|
262
|
+
# where the current Individual is the object.
|
|
263
|
+
#
|
|
264
|
+
def inboundAssociations()
|
|
265
|
+
if defined?(@inboundAssociations)
|
|
266
|
+
return @inboundAssociations
|
|
267
|
+
end
|
|
268
|
+
@inboundAssociations = Set.new
|
|
269
|
+
|
|
270
|
+
if @schema.options.verbose
|
|
271
|
+
puts "Searching for 'inbound' associations of individual #{short_name}"
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
sparql = <<sparql
|
|
275
|
+
SELECT DISTINCT ?individual ?predicate WHERE {
|
|
276
|
+
?individual
|
|
277
|
+
a owl:NamedIndividual ;
|
|
278
|
+
?predicate <#{uri}>
|
|
279
|
+
.
|
|
280
|
+
}
|
|
281
|
+
sparql
|
|
282
|
+
#if @schema.options.verbose
|
|
283
|
+
# puts " - SPARQL: #{sparql}"
|
|
284
|
+
#end
|
|
285
|
+
solutions = SPARQL.execute(sparql, @schema.model, { :prefixes => @schema.prefixes })
|
|
286
|
+
if @schema.options.verbose
|
|
287
|
+
puts " - Found #{solutions.count} associated 'inbound' Individual Associations"
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
solutions.each do |solution|
|
|
291
|
+
individual = Individual.withUri(solution[:individual], @schema)
|
|
292
|
+
predicate = solution[:predicate]
|
|
293
|
+
@inboundAssociations << IndividualAssociation.new(predicate, @schema, individual, self)
|
|
294
|
+
end
|
|
295
|
+
if @schema.options.verbose
|
|
296
|
+
puts " - Returning #{@inboundAssociations.size} associations for Individual #{short_name}"
|
|
297
|
+
end
|
|
298
|
+
return @inboundAssociations
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
private
|
|
302
|
+
def labelAsGraphvizRecord
|
|
303
|
+
lbl = label.gsub("_", " ")
|
|
304
|
+
if prefix and prefix == "r29" # TODO: make configurable
|
|
305
|
+
prefix = nil
|
|
306
|
+
end
|
|
307
|
+
lbl = prefix.nil? ? lbl : "#{lbl} | #{prefix}"
|
|
308
|
+
lbl = "#{lbl} |"
|
|
309
|
+
classes.each do |klass|
|
|
310
|
+
lbl += " #{klass.short_name} |"
|
|
311
|
+
end
|
|
312
|
+
lbl.chomp!(" |")
|
|
313
|
+
#puts "---------#{lbl}------"
|
|
314
|
+
return lbl
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
public
|
|
318
|
+
#
|
|
319
|
+
# Add the current Individual as a GraphViz node to the given collection of nodes
|
|
320
|
+
# and to the given graph. Return the collection of nodes.
|
|
321
|
+
#
|
|
322
|
+
def addAsGraphvizNode (graph_, nodes_, edges_, level_, maxLevel_ = 0)
|
|
323
|
+
if level_ < 1
|
|
324
|
+
return nodes_, edges_
|
|
325
|
+
end
|
|
326
|
+
if @schema.options.verbose
|
|
327
|
+
puts "- Processing Individual #{label}"
|
|
328
|
+
end
|
|
329
|
+
#
|
|
330
|
+
# No need to add a node twice
|
|
331
|
+
#
|
|
332
|
+
if nodes_.has_key?(uri)
|
|
333
|
+
return nodes_, edges_
|
|
334
|
+
end
|
|
335
|
+
options = {
|
|
336
|
+
:shape => :record,
|
|
337
|
+
:style => "rounded,filled",
|
|
338
|
+
:label => labelAsGraphvizRecord,
|
|
339
|
+
:tooltip => uri,
|
|
340
|
+
:peripheries => 1,
|
|
341
|
+
:margin => "0.21,0.055",
|
|
342
|
+
:fontcolor => :black,
|
|
343
|
+
:fontsize => 8,
|
|
344
|
+
:penwidth => 0.5,
|
|
345
|
+
:color => :black,
|
|
346
|
+
:fillcolor => "#FCFCFC",
|
|
347
|
+
:href => "#individual_#{short_name}"
|
|
348
|
+
}
|
|
349
|
+
if level_ == maxLevel_
|
|
350
|
+
options[:color] = "red"
|
|
351
|
+
options[:penwidth] = 1
|
|
352
|
+
end
|
|
353
|
+
node = graph_.add_nodes(escaped_uri, options)
|
|
354
|
+
nodes_[uri] = node
|
|
355
|
+
node.URL = "#individual_#{short_name}"
|
|
356
|
+
|
|
357
|
+
#if hasComment?
|
|
358
|
+
# node.tooltip = comment
|
|
359
|
+
#end
|
|
360
|
+
|
|
361
|
+
#classes.each do |klass|
|
|
362
|
+
# nodes_, edges_ = klass.addAsGraphvizNode(graph_, nodes_, edges_)
|
|
363
|
+
# Class.newGraphVizEdge(graph_, node, nodes_[klass.uri], false)
|
|
364
|
+
#end
|
|
365
|
+
|
|
366
|
+
inboundAssociations.each do |association|
|
|
367
|
+
nodes_, edges_ = association.addAsGraphVizEdge(graph_, nodes_, edges_, level_ - 1)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
outboundAssociations.each do |association|
|
|
371
|
+
nodes_, edges_ = association.addAsGraphVizEdge(graph_, nodes_, edges_, level_ - 1)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
return nodes_, edges_
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
public
|
|
378
|
+
#
|
|
379
|
+
# Generate a diagram for each Individual
|
|
380
|
+
#
|
|
381
|
+
def asSvg
|
|
382
|
+
if @schema.options.verbose
|
|
383
|
+
puts "Generating SVG for Individual #{short_name}"
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
g = GraphvizUtility.setDefaults(GraphViz.new(:G, :type => :digraph))
|
|
387
|
+
g[:rankdir] = "LR"
|
|
388
|
+
g.node[:fixedsize] = false
|
|
389
|
+
|
|
390
|
+
nodes = Hash.new
|
|
391
|
+
edges = Hash.new
|
|
392
|
+
|
|
393
|
+
nodes, edges = addAsGraphvizNode(g, nodes, edges, 5, 5)
|
|
394
|
+
|
|
395
|
+
return GraphvizUtility.embeddableSvg(g)
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module YOWL
|
|
2
|
+
|
|
3
|
+
class IndividualAssociation < YOWL::LabelledDocObject
|
|
4
|
+
|
|
5
|
+
attr_reader :domainIndividual
|
|
6
|
+
attr_reader :rangeIndividual
|
|
7
|
+
attr_reader :property
|
|
8
|
+
attr_reader :key
|
|
9
|
+
|
|
10
|
+
def initialize(resource, schema, domainIndividual, rangeIndividual)
|
|
11
|
+
|
|
12
|
+
if resource.nil?
|
|
13
|
+
raise "Problem"
|
|
14
|
+
end
|
|
15
|
+
super(resource, schema)
|
|
16
|
+
|
|
17
|
+
@domainIndividual = domainIndividual
|
|
18
|
+
@rangeIndividual = rangeIndividual
|
|
19
|
+
|
|
20
|
+
@key = "#{@domainIndividual.uri},#{@rangeIndividual.uri},#{label}".hash
|
|
21
|
+
|
|
22
|
+
#puts "Created IndividualAssociation #{@domainIndividual.uri},#{@rangeIndividual.uri}, #{uri}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def label
|
|
26
|
+
return short_name
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def hash
|
|
30
|
+
return key
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def eql?(other)
|
|
34
|
+
@key.eql? other.key
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Add the current IndividualAssociation as an edge to the given GraphViz graph,
|
|
39
|
+
# but check whether the IndividualAssociation refers to a Domain and Range class in
|
|
40
|
+
# the current schema and whether the IndividualAssociation has already been added
|
|
41
|
+
# to the graph (by checking the given edges collection).
|
|
42
|
+
#
|
|
43
|
+
def addAsGraphVizEdge(graph_, nodes_, edges_, level_)
|
|
44
|
+
|
|
45
|
+
if level_ < 1
|
|
46
|
+
return nodes_, edges_
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
nodes_, edges_ = @domainIndividual.addAsGraphvizNode(graph_, nodes_, edges_, level_)
|
|
50
|
+
nodes_, edges_ = @rangeIndividual.addAsGraphvizNode(graph_, nodes_, edges_, level_)
|
|
51
|
+
|
|
52
|
+
if edges_.has_key?(@key)
|
|
53
|
+
return nodes_, edges_
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
domainIndividualNode = nodes_[@domainIndividual.uri]
|
|
57
|
+
rangeIndividualNode = nodes_[@rangeIndividual.uri]
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# As the level_ parameter for the two calls to addAsGraphvizNode might have caused
|
|
61
|
+
# that one or both of these nodes are not generated, we have to check for this here.
|
|
62
|
+
#
|
|
63
|
+
if domainIndividualNode.nil? or rangeIndividualNode.nil?
|
|
64
|
+
return nodes_, edges_
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
options = {
|
|
68
|
+
:label => label.sub(/.*:/, ''),
|
|
69
|
+
:tooltip => uri.to_s,
|
|
70
|
+
:arrowhead => :open,
|
|
71
|
+
:arrowsize => 0.5,
|
|
72
|
+
:penwidth => 0.5
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
edges_[@key] = graph_.add_edges(domainIndividualNode, rangeIndividualNode, options)
|
|
76
|
+
|
|
77
|
+
return nodes_, edges_
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|