PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/mio.rdf/mio/rdf/mapping.py

https://code.google.com/p/mappa/
Python | 368 lines | 184 code | 52 blank | 132 comment | 36 complexity | 116f43a519fad3368c90f32f24c931b0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (c) 2007 - 2011 -- Lars Heuer - Semagia <http://www.semagia.com/>.
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. #
  10. # * Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. #
  13. # * Redistributions in binary form must reproduce the above
  14. # copyright notice, this list of conditions and the following
  15. # disclaimer in the documentation and/or other materials provided
  16. # with the distribution.
  17. #
  18. # * Neither the project name nor the names of the contributors may be
  19. # used to endorse or promote products derived from this software
  20. # without specific prior written permission.
  21. #
  22. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #
  34. """\
  35. :author: Lars Heuer (heuer[at]semagia.com)
  36. :organization: Semagia - http://www.semagia.com/
  37. :license: BSD license
  38. """
  39. from tm import mio, XSD, TMDM
  40. __all__ = ['MappingHandler']
  41. _TYPE_INSTANCE = mio.SUBJECT_IDENTIFIER, TMDM.type_instance
  42. _TYPE_INSTANCE_TYPE = mio.SUBJECT_IDENTIFIER, TMDM.type
  43. _TYPE_INSTANCE_INSTANCE = mio.SUBJECT_IDENTIFIER, TMDM.instance
  44. _SUPERTYPE_SUBTYPE = mio.SUBJECT_IDENTIFIER, TMDM.supertype_subtype
  45. _SUPERTYPE_SUBTYPE_SUPERTYPE = mio.SUBJECT_IDENTIFIER, TMDM.supertype
  46. _SUPERTYPE_SUBTYPE_SUBTYPE = mio.SUBJECT_IDENTIFIER, TMDM.subtype
  47. def _reference_from_object_iri(iri, is_blank_node):
  48. """\
  49. Returns either an item identifier (iff the IRI is a blank node)
  50. or subject identifier.
  51. """
  52. return mio.ITEM_IDENTIFIER, iri if is_blank_node else mio.SUBJECT_IDENTIFIER, iri
  53. class AbstractMapper(object):
  54. """\
  55. Common superclass for IMappers
  56. """
  57. def __init__(self, name):
  58. """\
  59. `name`
  60. The name of the mapper
  61. """
  62. self.name = name
  63. def handle_literal(self, handler, error_handler, subject, predicate_iri, value, datatype, language):
  64. """\
  65. Rejects the literal.
  66. """
  67. error_handler.reject_literal(self.name, value, datatype)
  68. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  69. """\
  70. Rejects an object
  71. """
  72. error_handler.reject_nonliteral(self.name, obj)
  73. class AbstractScopeTypeAwareMapper(AbstractMapper):
  74. """\
  75. """
  76. def __init__(self, name, scope=None, type=None):
  77. """\
  78. `name`
  79. Name of the mapper
  80. `scope`
  81. The scope.
  82. `type`
  83. The type.
  84. """
  85. super(AbstractScopeTypeAwareMapper, self).__init__(name)
  86. self._scope = scope if scope else None
  87. self._type = type
  88. def type(self, handler, pred=None):
  89. """
  90. Issues a ``IMapHandler#startType()``, ``IMapHandler#topicRef()``,
  91. ``IMapHandler#endType()`` event sequence.
  92. This method uses either a subject identifier reference from the provided
  93. `pred` or the overridden type (in case of a
  94. ``rdf-predicate rtm:type subject-identifier`` statment).
  95. `handler`
  96. The IMapHandler instance.
  97. `pred`
  98. A subject identifier reference or ``None``.
  99. """
  100. type_ = self._type if self._type else mio.SUBJECT_IDENTIFIER, pred
  101. self._handle_type(handler, type_)
  102. def _handle_type(self, handler, type):
  103. handler.startType()
  104. handler.topicRef(type)
  105. handler.endType()
  106. def role(self, handler, type, player):
  107. """\
  108. Issues events to the `handler` which create a role with the provided
  109. `type` and `player`.
  110. `handler`
  111. The handler which receives the events.
  112. `type`
  113. The role type
  114. `player`
  115. The role player
  116. """
  117. handler.startRole()
  118. self._handle_type(handler, type)
  119. handler.startPlayer()
  120. handler.topicRef(player)
  121. handler.endPlayer()
  122. handler.endRole()
  123. def process_scope(self, handler, additional_theme=None):
  124. """\
  125. Processes the scope, if any.
  126. This method must be called from the derived classes to process the scope.
  127. """
  128. scope = self._scope
  129. if not scope and not additional_theme:
  130. return
  131. handler.startScope()
  132. if additional_theme:
  133. handler.startTheme()
  134. handler.topicRef(additional_theme)
  135. handler.endTheme()
  136. if scope:
  137. for theme in scope:
  138. handler.startTheme()
  139. handler.topicRef(theme)
  140. handler.endTheme()
  141. handler.endScope()
  142. class AssociationMapper(AbstractScopeTypeAwareMapper):
  143. """\
  144. rtm:association implementation.
  145. """
  146. def __init__(self, subject_role, object_role, scope=None, type=None):
  147. """\
  148. """
  149. super(AssociationMapper, self).__init__('rtm:association', scope=scope, type=type)
  150. if not subject_role:
  151. raise mio.MIOException('The subject role must be provided')
  152. if not object_role:
  153. raise mio.MIOException('The object role must be provided')
  154. self._subject_role = subject_role
  155. self._object_role = object_role
  156. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  157. handler.startAssociation()
  158. self.type(handler, predicate_iri)
  159. self.role(handler, self._subject_role, subject)
  160. self.role(handler, self._object_role, _reference_from_object_iri(obj, is_blank_node))
  161. self.process_scope(handler)
  162. handler.endAssociation()
  163. class OccurrenceMapper(AbstractScopeTypeAwareMapper):
  164. """\
  165. rtm:occurrence implementation.
  166. """
  167. def __init__(self, scope=None, type=None, lang2scope=False):
  168. """\
  169. """
  170. super(OccurrenceMapper, self).__init__('rtm:occurrence', scope=scope, type=type)
  171. self._lang2scope = lang2scope
  172. def handle_literal(self, handler, error_handler, subject, predicate_iri, value, datatype, language):
  173. handler.startOccurrence()
  174. self.type(handler, predicate_iri)
  175. handler.value(value, datatype)
  176. self.process_scope(handler, language if self._lang2scope else None)
  177. handler.endOccurrence()
  178. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  179. if is_blank_node:
  180. error_handler.reject_blank_node(self.name)
  181. else:
  182. self.handle_literal(handler, error_handler, subject, predicate_iri, obj, XSD.anyURI, None)
  183. class NameMapper(AbstractScopeTypeAwareMapper):
  184. """\
  185. rtm:basename implementation.
  186. """
  187. def __init__(self, scope=None, type=None, lang2scope=False):
  188. """\
  189. """
  190. super(NameMapper, self).__init__('rtm:basename', scope=scope, type=type)
  191. self._lang2scope = lang2scope
  192. def handle_literal(self, handler, error_handler, subject, predicate_iri, value, datatype, language):
  193. handler.startName()
  194. self.type(handler, predicate_iri)
  195. handler.value(value)
  196. self.process_scope(handler, language if self._lang2scope else None)
  197. handler.endName()
  198. class TypeInstanceMapper(AbstractMapper):
  199. """\
  200. rtm:instance-of implementation (unconstrained scope)
  201. """
  202. def __new__(cls):
  203. if not '_the_instance' in cls.__dict__:
  204. cls._the_instance = object.__new__(cls)
  205. return cls._the_instance
  206. def __init__(self):
  207. super(TypeInstanceMapper, self).__init__('rtm:instance-of')
  208. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  209. handler.startIsa()
  210. handler.topicRef(_reference_from_object_iri(obj, is_blank_node));
  211. handler.endIsa()
  212. class TypeInstanceScopedMapper(AbstractScopeTypeAwareMapper):
  213. """\
  214. rtm:instance-of implementation with an associated scope.
  215. """
  216. def __init__(self, scope):
  217. super(TypeInstanceScopedMapper, self).__init__('rtm:instance-of', scope=scope, type=_TYPE_INSTANCE)
  218. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  219. handler.startAssociation()
  220. self.type(handler)
  221. self.role(handler, _TYPE_INSTANCE_INSTANCE, subject);
  222. self.role(handler, _TYPE_INSTANCE_TYPE, _reference_from_object_iri(obj, is_blank_node))
  223. self.process_scope(handler)
  224. handler.endAssociation()
  225. class SupertypeSubtypeMapper(AbstractScopeTypeAwareMapper):
  226. """\
  227. rtm:subtype-of implementation with an optional scope.
  228. """
  229. def __init__(self, scope):
  230. super(SupertypeSubtypeMapper, self).__init__('rtm:subtype-of', scope=scope, type=_SUPERTYPE_SUBTYPE)
  231. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  232. handler.startAssociation()
  233. self.type(handler)
  234. self.role(handler, _SUPERTYPE_SUBTYPE_SUBTYPE, subject);
  235. self.role(handler, _SUPERTYPE_SUBTYPE_SUPERTYPE, _reference_from_object_iri(obj, is_blank_node))
  236. self.process_scope(handler)
  237. handler.endAssociation()
  238. class IdentityMapper(AbstractMapper):
  239. """\
  240. rtm:subject-identifier, rtm:subject-locator, and rtm:source-locator mapping implementation.
  241. """
  242. def __new__(cls, kind):
  243. attr = '_the_instance_%s' % kind
  244. if not attr in cls.__dict__:
  245. setattr(cls, attr, object.__new__(cls))
  246. return getattr(cls, attr)
  247. def __init__(self, kind):
  248. super(IdentityMapper, self).__init__(kind == mio.SUBJECT_IDENTIFIER and 'rtm:subject-identifier' \
  249. or kind == mio.SUBJECT_LOCATOR and 'rtm:subject-locator' \
  250. or kind == mio.ITEM_IDENTIFIER and 'rtm:item-identifier')
  251. self._kind = kind
  252. def handle_object(self, handler, error_handler, subject, predicate_iri, obj, is_blank_node):
  253. if is_blank_node:
  254. error_handler.reject_blank_node(self.name)
  255. else:
  256. if mio.SUBJECT_IDENTIFIER == self._kind:
  257. handler.subjectIdentifier(obj)
  258. elif mio.SUBJECT_LOCATOR == self._kind:
  259. handler.subjectLocator(obj)
  260. else:
  261. handler.itemIdentifier(obj)
  262. class MappingHandler(object):
  263. """\
  264. Default IMappingHandler implementation that keeps the mapping in-memory.
  265. """
  266. def __init__(self):
  267. self.mapping = {}
  268. def start(self):
  269. pass
  270. def end(self):
  271. pass
  272. def handleComment(self, comment):
  273. pass
  274. def handlePrefix(self, prefix, iri):
  275. pass
  276. def handleAssociation(self, predicate, subject_role, object_role, scope=None, type=None):
  277. self.mapping[predicate] = AssociationMapper(subject_role=_sid(subject_role),
  278. object_role=_sid(object_role),
  279. scope=_sids(scope), type=_sid(type))
  280. def handleOccurrence(self, predicate, scope=None, type=None, lang2scope=False):
  281. self.mapping[predicate] = OccurrenceMapper(scope=_sids(scope), type=_sid(type), lang2scope=lang2scope)
  282. def handleName(self, predicate, scope=None, type=None, lang2scope=False):
  283. self.mapping[predicate] = NameMapper(scope=_sids(scope), type=_sid(type), lang2scope=lang2scope)
  284. def handleInstanceOf(self, predicate, scope=None):
  285. if not scope:
  286. self.mapping[predicate] = TypeInstanceMapper()
  287. else:
  288. self.mapping[predicate] = TypeInstanceScopedMapper(scope=_sids(scope))
  289. def handleSubtypeOf(self, predicate, scope=None):
  290. self.mapping[predicate] = SupertypeSubtypeMapper(scope=_sids(scope))
  291. def handleSubjectIdentifier(self, predicate):
  292. self.mapping[predicate] = IdentityMapper(mio.SUBJECT_IDENTIFIER)
  293. def handleSubjectLocator(self, predicate):
  294. self.mapping[predicate] = IdentityMapper(mio.SUBJECT_LOCATOR)
  295. def handleItemIdentifier(self, predicate):
  296. self.mapping[predicate] = IdentityMapper(mio.ITEM_IDENTIFIER)
  297. def _sids(iris):
  298. if not iris:
  299. return None
  300. return [(mio.SUBJECT_IDENTIFIER, iri) for iri in iris]
  301. def _sid(iri):
  302. if not iri:
  303. return None
  304. return mio.SUBJECT_IDENTIFIER, iri