web/views/owl.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """produces some Ontology Web Language schema and views
       
    19 
       
    20 """
       
    21 __docformat__ = "restructuredtext en"
       
    22 from cubicweb import _
       
    23 
       
    24 from six.moves import range
       
    25 
       
    26 from logilab.mtconverter import TransformError, xml_escape
       
    27 
       
    28 from cubicweb.view import StartupView, EntityView
       
    29 from cubicweb.predicates import none_rset, match_view
       
    30 from cubicweb.web.action import Action
       
    31 from cubicweb.web.views import schema
       
    32 
       
    33 OWL_CARD_MAP = {'1': '<rdf:type rdf:resource="&owl;FunctionalProperty"/>',
       
    34                 '?': '<owl:maxCardinality rdf:datatype="&xsd;int">1</owl:maxCardinality>',
       
    35                 '+': '<owl:minCardinality rdf:datatype="&xsd;int">1</owl:minCardinality>',
       
    36                 '*': ''
       
    37                 }
       
    38 
       
    39 OWL_TYPE_MAP = {'String': 'xsd:string',
       
    40                 'Bytes': 'xsd:byte',
       
    41                 'Password': 'xsd:byte',
       
    42 
       
    43                 'Boolean': 'xsd:boolean',
       
    44                 'Int': 'xsd:int',
       
    45                 'BigInt': 'xsd:int',
       
    46                 'Float': 'xsd:float',
       
    47                 'Decimal' : 'xsd:decimal',
       
    48 
       
    49                 'Date':'xsd:date',
       
    50                 'Datetime': 'xsd:dateTime',
       
    51                 'TZDatetime': 'xsd:dateTime',
       
    52                 'Time': 'xsd:time',
       
    53                 'TZTime': 'xsd:time',
       
    54                 'Interval': 'xsd:duration'
       
    55                 }
       
    56 
       
    57 OWL_OPENING_ROOT = u'''<?xml version="1.0" encoding="UTF-8"?>
       
    58 <!DOCTYPE rdf:RDF [
       
    59         <!ENTITY owl "http://www.w3.org/2002/07/owl#" >
       
    60         <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
       
    61 ]>
       
    62 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       
    63     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
       
    64     xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
       
    65     xmlns:owl="http://www.w3.org/2002/07/owl#"
       
    66     xmlns="http://logilab.org/owl/ontologies/%(appid)s#"
       
    67     xmlns:%(appid)s="http://logilab.org/owl/ontologies/%(appid)s#"
       
    68     xmlns:base="http://logilab.org/owl/ontologies/%(appid)s">
       
    69 
       
    70   <owl:Ontology rdf:about="">
       
    71     <rdfs:comment>
       
    72     %(appid)s Cubicweb OWL Ontology
       
    73     </rdfs:comment>
       
    74   </owl:Ontology>'''
       
    75 
       
    76 OWL_CLOSING_ROOT = u'</rdf:RDF>'
       
    77 
       
    78 
       
    79 class OWLView(StartupView):
       
    80     """This view export in owl format schema database. It is the TBOX"""
       
    81     __regid__ = 'owl'
       
    82     title = _('owl')
       
    83     templatable = False
       
    84     content_type = 'application/xml' # 'text/xml'
       
    85 
       
    86     def call(self, writeprefix=True):
       
    87         skipmeta = int(self._cw.form.get('skipmeta', True))
       
    88         if writeprefix:
       
    89             self.w(OWL_OPENING_ROOT % {'appid': self._cw.vreg.schema.name})
       
    90         self.visit_schema(skiptypes=skipmeta and schema.SKIP_TYPES or ())
       
    91         if writeprefix:
       
    92             self.w(OWL_CLOSING_ROOT)
       
    93 
       
    94     def should_display_rschema(self, eschema, rschema, role):
       
    95         return not rschema in self.skiptypes and (
       
    96             rschema.may_have_permission('read', self._cw, eschema, role))
       
    97 
       
    98     def visit_schema(self, skiptypes):
       
    99         """get a layout for a whole schema"""
       
   100         self.skiptypes = skiptypes
       
   101         entities = sorted(eschema for eschema in self._cw.vreg.schema.entities()
       
   102                           if not eschema.final or eschema in skiptypes)
       
   103         self.w(u'<!-- classes definition -->')
       
   104         for eschema in entities:
       
   105             self.visit_entityschema(eschema)
       
   106             self.w(u'<!-- property definition -->')
       
   107             self.visit_property_schema(eschema)
       
   108             self.w(u'<!-- datatype property -->')
       
   109             self.visit_property_object_schema(eschema)
       
   110 
       
   111     def visit_entityschema(self, eschema):
       
   112         """get a layout for an entity OWL schema"""
       
   113         self.w(u'<owl:Class rdf:ID="%s">'% eschema)
       
   114         self.w(u'<!-- relations -->')
       
   115         for rschema, targetschemas, role in eschema.relation_definitions():
       
   116             if not self.should_display_rschema(eschema, rschema, role):
       
   117                 continue
       
   118             for oeschema in targetschemas:
       
   119                 card = rschema.role_rdef(eschema, oeschema, role).role_cardinality(role)
       
   120                 cardtag = OWL_CARD_MAP[card]
       
   121                 if cardtag:
       
   122                     self.w(u'''<rdfs:subClassOf>
       
   123  <owl:Restriction>
       
   124   <owl:onProperty rdf:resource="#%s"/>
       
   125   %s
       
   126  </owl:Restriction>
       
   127 </rdfs:subClassOf>''' % (rschema, cardtag))
       
   128 
       
   129         self.w(u'<!-- attributes -->')
       
   130         for rschema, aschema in eschema.attribute_definitions():
       
   131             if not self.should_display_rschema(eschema, rschema, 'subject'):
       
   132                 continue
       
   133             self.w(u'''<rdfs:subClassOf>
       
   134   <owl:Restriction>
       
   135    <owl:onProperty rdf:resource="#%s"/>
       
   136    <rdf:type rdf:resource="&owl;FunctionalProperty"/>
       
   137   </owl:Restriction>
       
   138 </rdfs:subClassOf>''' % rschema)
       
   139         self.w(u'</owl:Class>')
       
   140 
       
   141     def visit_property_schema(self, eschema):
       
   142         """get a layout for property entity OWL schema"""
       
   143         for rschema, targetschemas, role in eschema.relation_definitions():
       
   144             if not self.should_display_rschema(eschema, rschema, role):
       
   145                 continue
       
   146             for oeschema in targetschemas:
       
   147                 self.w(u'''<owl:ObjectProperty rdf:ID="%s">
       
   148  <rdfs:domain rdf:resource="#%s"/>
       
   149  <rdfs:range rdf:resource="#%s"/>
       
   150 </owl:ObjectProperty>''' % (rschema, eschema, oeschema.type))
       
   151 
       
   152     def visit_property_object_schema(self, eschema):
       
   153         for rschema, aschema in eschema.attribute_definitions():
       
   154             if not self.should_display_rschema(eschema, rschema, 'subject'):
       
   155                 continue
       
   156             self.w(u'''<owl:DatatypeProperty rdf:ID="%s">
       
   157   <rdfs:domain rdf:resource="#%s"/>
       
   158   <rdfs:range rdf:resource="%s"/>
       
   159 </owl:DatatypeProperty>''' % (rschema, eschema, OWL_TYPE_MAP[aschema.type]))
       
   160 
       
   161 
       
   162 class OWLABOXView(EntityView):
       
   163     '''This view represents a part of the ABOX for a given entity.'''
       
   164     __regid__ = 'owlabox'
       
   165     title = _('owlabox')
       
   166     templatable = False
       
   167     content_type = 'application/xml' # 'text/xml'
       
   168 
       
   169     def call(self):
       
   170         self.w(OWL_OPENING_ROOT % {'appid': self._cw.vreg.schema.name})
       
   171         for i in range(self.cw_rset.rowcount):
       
   172             self.cell_call(i, 0)
       
   173         self.w(OWL_CLOSING_ROOT)
       
   174 
       
   175     def cell_call(self, row, col):
       
   176         self.wview('owlaboxitem', self.cw_rset, row=row, col=col)
       
   177 
       
   178 
       
   179 class OWLABOXItemView(EntityView):
       
   180     '''This view represents a part of the ABOX for a given entity.'''
       
   181     __regid__ = 'owlaboxitem'
       
   182     templatable = False
       
   183     content_type = 'application/xml' # 'text/xml'
       
   184 
       
   185     def cell_call(self, row, col):
       
   186         entity = self.cw_rset.complete_entity(row, col)
       
   187         eschema = entity.e_schema
       
   188         self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
       
   189         self.w(u'<!--attributes-->')
       
   190         for rschema, aschema in eschema.attribute_definitions():
       
   191             if rschema.meta:
       
   192                 continue
       
   193             rdef = rschema.rdef(eschema, aschema)
       
   194             if not rdef.may_have_permission('read', self._cw):
       
   195                 continue
       
   196             aname = rschema.type
       
   197             if aname == 'eid':
       
   198                 continue
       
   199             try:
       
   200                 attr = entity.printable_value(aname, format='text/plain')
       
   201                 if attr:
       
   202                     self.w(u'<%s>%s</%s>' % (aname, xml_escape(attr), aname))
       
   203             except TransformError:
       
   204                 pass
       
   205         self.w(u'<!--relations -->')
       
   206         for rschema, targetschemas, role in eschema.relation_definitions():
       
   207             if rschema.meta:
       
   208                 continue
       
   209             for tschema in targetschemas:
       
   210                 rdef = rschema.role_rdef(eschema, tschema, role)
       
   211                 if rdef.may_have_permission('read', self._cw):
       
   212                     break
       
   213             else:
       
   214                 # no read perms to any relation of this type. Skip.
       
   215                 continue
       
   216             if role == 'object':
       
   217                 attr = 'reverse_%s' % rschema.type
       
   218             else:
       
   219                 attr = rschema.type
       
   220             for x in getattr(entity, attr):
       
   221                 self.w(u'<%s>%s %s</%s>' % (attr, x.__regid__, x.eid, attr))
       
   222         self.w(u'</%s>'% eschema)
       
   223 
       
   224 
       
   225 class DownloadOWLSchemaAction(Action):
       
   226     __regid__ = 'download_as_owl'
       
   227     __select__ = none_rset() & match_view('schema')
       
   228 
       
   229     category = 'mainactions'
       
   230     title = _('download schema as owl')
       
   231 
       
   232     def url(self):
       
   233         return self._cw.build_url('view', vid='owl')