summaryrefslogtreecommitdiff
path: root/lib/rdf_provider.rb
blob: 7fa3eccc0cb98babe4478036703aae0bd1485d12 (plain)
1
2
3
4
5
6
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

class String
  def convert_underscore
    gsub(/_./) do |m|
      m.gsub!(/^_/,"")
      m.upcase
    end
  end
end

module Lib
  module RDFProvider
    
    def to_rdf
      HashToOwl.to_rdf(self)
    end
    
    def uri
      raise "not implemented"
    end
    
    def rdf_title
      raise "not implemented"
    end
    
    # the rdf output is generated from the hash that is provided by this method
    # the keys in the hash structure are used to defined type of the resource (literal, objectProperty, dataProperty)
    # example: if the structure should contain a literal named "size" with value 5
    # * add :property_xy => 5 to your hash
    # * make sure literal?(:property_xy) returns true
    # * literal_name(:property_xy) must return "size"
    #
    def get_content_as_hash
      raise "not implemented"
    end
    
    def to_yaml
      get_content_as_hash.to_yaml
    end
    
    def rdf_ignore?( prop )
      self.class::IGNORE.index( prop ) != nil
    end
    
    def literal?( prop )
      self.class::LITERALS.index( prop ) != nil
    end
    
    def literal_name( prop )
      if self.class::LITERAL_NAMES.has_key?(prop)
        self.class::LITERAL_NAMES[prop]
      else
        OT[prop.to_s.convert_underscore]
      end
    end
    
    def object_property?( prop )
      self.class::OBJECT_PROPERTIES.has_key?( prop )
    end
    
    def object_property_name( prop )
      return self.class::OBJECT_PROPERTIES[ prop ]
    end
    
    def object_type( prop )
      return self.class::OBJECTS[ prop ]
    end
  
    def class?(prop)
      self.class::CLASSES.has_key?( prop )
    end
    
    def class_name( prop )
      return self.class::CLASSES[ prop ]
    end
    
  end
  
  class HashToOwl
    #include OpenTox::Owl
    
    def self.to_rdf( rdf_provider )
      
      owl = OpenTox::Owl.create(rdf_provider.rdf_title, rdf_provider.uri )
      toOwl = HashToOwl.new(owl)
      toOwl.add_content(rdf_provider)
      toOwl.rdf
    end
  
    def add_content( rdf_provider ) 
      @rdf_provider = rdf_provider
      recursiv_add_content( @rdf_provider.get_content_as_hash, @owl.root_node )
    end
    
    def rdf
      @owl.rdf
    end
    
    private
    def initialize(owl)
      @owl = owl
      @model = owl.model
    end
    
    def recursiv_add_content( output, node )
      output.each do |k,v|
        if v==nil
          LOGGER.warn "skipping nil value: "+k.to_s
          next
        end
        if @rdf_provider.rdf_ignore?(k)
          #do nothing
        elsif v.is_a?(Hash)
          new_node = add_class( k, node )
          recursiv_add_content( v, new_node )
        elsif v.is_a?(Array)
          v.each do |value|
            if @rdf_provider.class?(k)
              new_node = add_class( k, node )
              recursiv_add_content( value, new_node )
            else
              add_object_property( k, value, node)
            end
          end
        elsif @rdf_provider.literal?(k)
          set_literal( k, v, node)
        elsif @rdf_provider.object_property?(k)
          add_object_property( k, v, node)
        else
          raise "illegal value k:"+k.to_s+" v:"+v.to_s
        end
      end
    end
  
    def add_class( property, node )
      raise "no object prop: "+property.to_s unless @rdf_provider.object_property?(property)
      raise "no class name: "+property.to_s unless @rdf_provider.class_name(property)
      # to avoid anonymous nodes, make up uris for sub-objects
      # use counter to make sure each uri is unique
      # for example we will get ../confusion_matrix_cell/1, ../confusion_matrix_cell/2, ...
      count = 1
      while (true)
        res = Redland::Resource.new( File.join(node.uri.to_s,property.to_s+"/"+count.to_s) )  
        break if @model.subject(@rdf_provider.object_property_name(property), res).nil?
        count += 1
      end
      clazz = Redland::Resource.new(@rdf_provider.class_name(property))
      @model.add res, RDF['type'], clazz
      @model.add res, DC['title'], clazz
      @model.add clazz, RDF['type'], OWL['Class']
      @model.add DC['title'], RDF['type'],OWL['AnnotationProperty']
      
      objectProp = Redland::Resource.new(@rdf_provider.object_property_name(property))
      @model.add objectProp, RDF['type'], OWL['ObjectProperty']
      @model.add node, objectProp, res
      return res
    end
    
    def set_literal(property, value, node )
      raise "empty literal value "+property.to_s if value==nil || value.to_s.size==0
      raise "no literal name "+propety.to_s unless @rdf_provider.literal_name(property)
      begin
        l = @model.object(subject, @rdf_provider.literal_name(property))
        @model.delete node, @rdf_provider.literal_name(property), l
      rescue
      end
      literalProp =  Redland::Resource.new(@rdf_provider.literal_name(property))
      @model.add literalProp, RDF['type'],OWL['AnnotationProperty']
      @model.add node, literalProp, Redland::Literal.create(value)
    end
    
    def add_object_property(property, value, node )
      raise "empty object property value "+property.to_s if value==nil || value.to_s.size==0
      raise "no object property name "+propety.to_s unless @rdf_provider.object_property_name(property)
      raise "no object type "+property.to_s unless @rdf_provider.object_type(property)
      
      objectProp = Redland::Resource.new(@rdf_provider.object_property_name(property))
      @model.add objectProp, RDF['type'], OWL['ObjectProperty']
      
      val = Redland::Resource.new(value)
      type = Redland::Resource.new(@rdf_provider.object_type(property))
      @model.add node, objectProp, val
      @model.add val, RDF['type'], type
      @model.add type, RDF['type'], OWL['Class']
    end
    
  end
end