Module: Solis::Shape
- Defined in:
- lib/solis/shape.rb,
lib/solis/shape/reader/csv.rb,
lib/solis/shape/reader/file.rb,
lib/solis/shape/reader/sheet.rb
Defined Under Namespace
Modules: Reader
Class Method Summary collapse
Class Method Details
.from_graph(graph) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/solis/shape.rb', line 7 def self.from_graph(graph) class << self def parse_graph(graph) shapes = {} #puts query.execute(graph).to_csv query.execute(graph) do |solution| parse_solution(shapes, solution) end add_labels(shapes, graph) # shapes = add_missing_attributes(shapes) shapes rescue Solis::Error::GeneralError => e raise "Unable to parse shapes: #{e.}" end def lookup_datatype(datatype, node) if datatype =~ /^http:\/\/www.w3.org\/2001\/XMLSchema#/ case datatype when /^http:\/\/www.w3.org\/2001\/XMLSchema#anyURI/ :anyuri when /http:\/\/www.w3.org\/2001\/XMLSchema#duration/ :duration when /http:\/\/www.w3.org\/2001\/XMLSchema#integer/ :integer when /http:\/\/www.w3.org\/2001\/XMLSchema#int/ :integer when /http:\/\/www.w3.org\/2001\/XMLSchema#dateTime/ :datetime when /http:\/\/www.w3.org\/2001\/XMLSchema#date/ :date when /http:\/\/www.w3.org\/2001\/XMLSchema#time/ :time when /http:\/\/www.w3.org\/2001\/XMLSchema#gYear/ :year when /http:\/\/www.w3.org\/2001\/XMLSchema#string/ :string when /http:\/\/www.w3.org\/2001\/XMLSchema#boolean/ :boolean when /http:\/\/www.w3.org\/2001\/XMLSchema#float/ :float when /http:\/\/www.w3.org\/2001\/XMLSchema#double/ :double else #puts datatype.split('#').last.to_sym :string end elsif datatype =~ /http:\/\/schema.org\// case datatype when /http:\/\/schema.org\/temporalCoverage/ :temporal_coverage else #puts datatype.split('#').last.to_sym :string end elsif datatype =~ /http:\/\/www.w3.org\/2006\/time/ case datatype when /http:\/\/www.w3.org\/2006\/time#DateTimeInterval/ :datetime_interval else #puts datatype.split('#').last.to_sym :string end elsif datatype.nil? && node.is_a?(RDF::URI) node.value.split('/').last.gsub(/Shape$/, '').to_sym # normalize ex."https://data.q.odis.be/person#Name" to Name #node.value.split('/').last.gsub(/Shape$/, '').split('#').last.to_sym #node.value.split('/').last.gsub(/Shape$/, '').gsub('#','').camelize.to_sym elsif datatype =~ /datatypes\/edtf/ || datatype =~ /edtf$/i # Library of Congress EDTF datatype :edtf elsif datatype =~ /^http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns/ case datatype when /http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#langString/ :lang_string when /http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#JSON/ :json else :string end else :string end end def parse_solution(shapes, solution) shape_rdf = solution.targetClass shape_node = solution.targetNode if solution.bound?(:targetNode) shape_name = solution.className.value attribute_name = solution.attributeName.value if solution.bound?(:attributeName) comment = solution.comment.value if solution.bound?(:comment) attribute_rdf = solution.attributePath.value if solution.bound?(:attributePath) attribute_datatype_rdf = solution.attributeDatatype.value if solution.bound?(:attributeDatatype) attribute_min_count = solution.bound?(:attributeMinCount) ? solution.attributeMinCount.value.to_i : 0 attribute_max_count = solution.bound?(:attributeMaxCount) ? solution.attributeMaxCount.value.to_i : nil attribute_node_kind = solution.attributeNodeKind if solution.bound?(:attributeNodeKind) attribute_node = solution.attributeNode if solution.bound?(:attributeNode) attribute_class = solution.attributeClass if solution.bound?(:attributeClass) attribute_comment = solution.attributeComment if solution.bound?(:attributeComment) attribute_order = solution.attributeOrder if solution.bound?(:attributeOrder) attribute_group = solution.attributeGroup if solution.bound?(:attributeGroup) attribute_max_count = 1 if solution.bound?(:attributeUniqueLang) && solution.attributeUniqueLang.value.eql?('true') # if solution.bound?(:attributeOr) # pp solution # end attribute_node = attribute_class if attribute_name && attribute_datatype_rdf.nil? && attribute_node.nil? shape = shapes.key?(shape_name) ? shapes[shape_name] : { target_class: nil, target_node: nil, attributes: {} } shape[:target_class] = shape_rdf shape[:target_node] = shape_node shape[:comment] = comment shape[:attributes][attribute_name] = { path: attribute_rdf, datatype_rdf: attribute_datatype_rdf, datatype: lookup_datatype(attribute_datatype_rdf, attribute_node), mincount: attribute_min_count, maxcount: attribute_max_count, order: attribute_order, group: attribute_group, node: attribute_node, node_kind: attribute_node_kind, class: attribute_class, comment: attribute_comment } shape[:attributes].delete_if { |k, _| k.nil? } shapes[shape_name] = shape end # Reads the rdfs:label statements of every node shape and property shape into # { nl: 'Publiceren', en: 'Publish' }. This is a second pass on purpose: adding # rdfs:label to the main query would multiply every solution by the number of # languages. def add_labels(shapes, graph) graph.query([nil, RDF.type, RDF::Vocab::SHACL.NodeShape]) do |node_shape| shape_name = name_of(graph, node_shape.subject) shape = shapes[shape_name] next if shape.nil? shape[:label] = labels_of(graph, node_shape.subject) graph.query([node_shape.subject, RDF::Vocab::SHACL.property, nil]) do |property| attribute = shape[:attributes][name_of(graph, property.object)] next if attribute.nil? attribute[:label] = labels_of(graph, property.object) end end shapes end def name_of(graph, subject) graph.query([subject, RDF::Vocab::SHACL.name, nil]).first&.object&.value end def labels_of(graph, subject) labels = {} graph.query([subject, RDF::RDFS.label, nil]).each do |statement| literal = statement.object language = Solis::LanguageTag.normalize(literal.language) if literal.is_a?(RDF::Literal) next if language.nil? labels[language] = literal.value end labels end def query SPARQL.parse %( PREFIX sh: <http://www.w3.org/ns/shacl#> PREFIX rdfv: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> SELECT ?targetClass ?targetNode ?comment ?className ?attributePath ?attributeName ?attributeDatatype ?attributeMinCount ?attributeMaxCount ?attributeOr ?attributeClass ?attributeNode ?attributeNodeKind ?attributeComment ?attributeOrder ?attributeGroup ?attributeUniqueLang ?o WHERE { ?s a sh:NodeShape; sh:targetClass ?targetClass ; sh:node ?targetNode ; sh:description ?comment ; sh:name ?className . OPTIONAL{ ?s sh:property ?attributes . ?attributes sh:name ?attributeName ; sh:path ?attributePath ; OPTIONAL{ ?attributes sh:datatype ?attributeDatatype } . OPTIONAL{ ?attributes sh:minCount ?attributeMinCount } . OPTIONAL{ ?attributes sh:maxCount ?attributeMaxCount } . OPTIONAL{ ?attributes sh:or ?attributeOr } . OPTIONAL{ ?attributes sh:class ?attributeClass } . OPTIONAL{ ?attributes sh:nodeKind ?attributeNodeKind } . OPTIONAL{ ?attributes sh:node ?attributeNode } . OPTIONAL{ ?attributes sh:description ?attributeComment } . OPTIONAL{ ?attributes sh:order ?attributeOrder } . OPTIONAL{ ?attributes sh:group ?attributeGroup } . OPTIONAL{ ?attributes sh:uniqueLang ?attributeUniqueLang } . }. } ) end def add_missing_attributes(shapes) shapes.each do |shape| if shape[1].is_a?(Hash) graph_name = shape[1][:target_class].value.split(shape[1][:target_class].path).first attributes = shape[1][:attributes] unless attributes.key?('id') if shape[1][:target_class] == shape[1][:target_node] attributes['id'] = { "path": "#{graph_name}/id", "datatype_rdf": "http://www.w3.org/2001/XMLSchema#string", "datatype": "string", "mincount": 1, "maxcount": 1, "order": nil, "group": nil, "node": nil, "node_kind": nil, "class": nil, "comment": RDF::Literal.new("UUID", datatype: RDF::XSD.string) } shape[1][:attributes] = attributes end end end end shapes end end parse_graph(graph) end |