/extensions/SemanticMediaWiki/includes/export/SMW_Exp_Data.php

https://github.com/ChuguluGames/mediawiki-svn · PHP · 255 lines · 131 code · 18 blank · 106 comment · 34 complexity · 9ee1b4ed1021fcdb608114c4b73e8a83 MD5 · raw file

  1. <?php
  2. /**
  3. * SMWExpData is a class representing semantic data that is ready for easy
  4. * serialisation in OWL or RDF.
  5. *
  6. * @author Markus Krötzsch
  7. * @file
  8. * @ingroup SMW
  9. */
  10. /**
  11. * SMWExpData is a data container for export-ready semantic content. It is
  12. * organised as a tree-shaped data structure with one root subject and zero
  13. * or more children connected with labelled edges to the root. Children are
  14. * again SMWExpData objects, and edges are annotated with SMWExpNsElements
  15. * specifying properties.
  16. * @note We do not allow property element without namespace abbreviation
  17. * here. Property aabbreviations are mandatory for some serialisations.
  18. *
  19. * @ingroup SMW
  20. */
  21. class SMWExpData extends SMWExpElement {
  22. /**
  23. * The subject of the data that we store.
  24. * @var SMWExpResource
  25. */
  26. protected $m_subject;
  27. /**
  28. * Array mapping property URIs to arrays their values, given as
  29. * SMWExpElement objects.
  30. * @var array of array of SMWElement
  31. */
  32. protected $m_children = array();
  33. /**
  34. * Array mapping property URIs to arrays their SMWExpResource
  35. * @var array of SMWExpResource
  36. */
  37. protected $m_edges = array();
  38. /**
  39. * Constructor. $subject is the SMWExpResource for the
  40. * subject about which this SMWExpData is.
  41. */
  42. public function __construct( SMWExpResource $subject ) {
  43. parent::__construct( $subject->getDataItem() );
  44. $this->m_subject = $subject;
  45. }
  46. /**
  47. * Turn an array of SMWExpElements into an RDF collection.
  48. *
  49. * @param $elements array of SMWExpElement
  50. * @return SMWExpData
  51. */
  52. public static function makeCollection( array $elements ) {
  53. if ( count( $elements ) == 0 ) {
  54. return new SMWExpData( SMWExporter::getSpecialNsResource( 'rdf', 'nil' ) );
  55. } else {
  56. $rdftype = SMWExporter::getSpecialNsResource( 'rdf', 'type' );
  57. $rdffirst = SMWExporter::getSpecialNsResource( 'rdf', 'first' );
  58. $rdfrest = SMWExporter::getSpecialNsResource( 'rdf', 'rest' );
  59. $result = new SMWExpData( new SMWExpResource( '' ) ); // bnode
  60. $result->addPropertyObjectValue( $rdftype, new SMWExpData( SMWExporter::getSpecialNsResource( 'rdf', 'List' ) ) );
  61. $result->addPropertyObjectValue( $rdffirst, array_shift( $elements ) );
  62. $result->addPropertyObjectValue( $rdfrest, SMWExpData::makeCollection( $elements ) );
  63. return $result;
  64. }
  65. }
  66. /**
  67. * Return subject to which the stored semantic annotation refer to.
  68. *
  69. * @return SMWExpResource
  70. */
  71. public function getSubject() {
  72. return $this->m_subject;
  73. }
  74. /**
  75. * Store a value for a property identified by its title object. No
  76. * duplicate elimination as this is usually done in SMWSemanticData
  77. * already (which is typically used to generate this object).
  78. *
  79. * @param SMWExpNsResource $property
  80. * @param SMWExpData $child
  81. */
  82. public function addPropertyObjectValue( SMWExpNsResource $property, SMWExpElement $child ) {
  83. if ( !array_key_exists( $property->getUri(), $this->m_edges ) ) {
  84. $this->m_children[$property->getUri()] = array();
  85. $this->m_edges[$property->getUri()] = $property;
  86. }
  87. $this->m_children[$property->getUri()][] = $child;
  88. }
  89. /**
  90. * Return the list of SMWExpResource objects for all properties for
  91. * which some values have been given.
  92. *
  93. * @return array of SMWExpResource
  94. */
  95. public function getProperties() {
  96. return $this->m_edges;
  97. }
  98. /**
  99. * Return the list of SMWExpElement values associated to some property
  100. * (element).
  101. *
  102. * @return array of SMWExpElement
  103. */
  104. public function getValues( SMWExpResource $property ) {
  105. if ( array_key_exists( $property->getUri(), $this->m_children ) ) {
  106. return $this->m_children[$property->getUri()];
  107. } else {
  108. return array();
  109. }
  110. }
  111. /**
  112. * Return the list of SMWExpData values associated to some property that is
  113. * specifed by a standard namespace id and local name.
  114. *
  115. * @param $namespaceId string idetifying a known special namespace (e.g. "rdf")
  116. * @param $localName string of local name (e.g. "type")
  117. * @return array of SMWExpData
  118. */
  119. public function getSpecialValues( $namespaceId, $localName ) {
  120. $pe = SMWExporter::getSpecialNsResource( $namespaceId, $localName );
  121. return $this->getValues( $pe );
  122. }
  123. /**
  124. * This function finds the main type (class) element of the subject
  125. * based on the current property assignments. It returns this type
  126. * element (SMWExpElement) and removes the according type assignement
  127. * from the data. If no type is assigned, the element for rdf:Resource
  128. * is returned.
  129. *
  130. * @note Under all normal conditions, the result will be an
  131. * SMWExpResource.
  132. *
  133. * @return SMWExpElement
  134. */
  135. public function extractMainType() {
  136. $pe = SMWExporter::getSpecialNsResource( 'rdf', 'type' );
  137. if ( array_key_exists( $pe->getUri(), $this->m_children ) ) {
  138. $result = array_shift( $this->m_children[$pe->getUri()] );
  139. if ( count( $this->m_children[$pe->getUri()] ) == 0 ) {
  140. unset( $this->m_edges[$pe->getUri()] );
  141. unset( $this->m_children[$pe->getUri()] );
  142. }
  143. return ( $result instanceof SMWExpData ) ? $result->getSubject() : $result;
  144. } else {
  145. return SMWExporter::getSpecialNsResource( 'rdf', 'Resource' );
  146. }
  147. }
  148. /**
  149. * Check if this element encodes an RDF list, and if yes return an
  150. * array of SMWExpElements corresponding to the collection elements in
  151. * the specified order. Otherwise return false.
  152. * The method only returns lists that can be encoded using
  153. * parseType="Collection" in RDF/XML, i.e. only lists of non-literal
  154. * resources.
  155. *
  156. * @return mixed array of SMWExpElement (but not SMWExpLiteral) or false
  157. */
  158. public function getCollection() {
  159. $rdftypeUri = SMWExporter::getSpecialNsResource( 'rdf', 'type' )->getUri();
  160. $rdffirstUri = SMWExporter::getSpecialNsResource( 'rdf', 'first' )->getUri();
  161. $rdfrestUri = SMWExporter::getSpecialNsResource( 'rdf', 'rest' )->getUri();
  162. $rdfnilUri = SMWExporter::getSpecialNsResource( 'rdf', 'nil' )->getUri();
  163. // first check if we are basically an RDF List:
  164. if ( ( $this->m_subject->isBlankNode() ) &&
  165. ( count( $this->m_children ) == 3 ) &&
  166. ( array_key_exists( $rdftypeUri, $this->m_children ) ) &&
  167. ( count( $this->m_children[$rdftypeUri] ) == 1 ) &&
  168. ( array_key_exists( $rdffirstUri, $this->m_children ) ) &&
  169. ( count( $this->m_children[$rdffirstUri] ) == 1 ) &&
  170. !( end( $this->m_children[$rdffirstUri] ) instanceof SMWExpLiteral ) &&
  171. // (parseType collection in RDF not possible with literals :-/)
  172. ( array_key_exists( $rdfrestUri, $this->m_children ) ) &&
  173. ( count( $this->m_children[$rdfrestUri] ) == 1 ) ) {
  174. $typedata = end( $this->m_children[$rdftypeUri] );
  175. $rdflistUri = SMWExporter::getSpecialNsResource( 'rdf', 'List' )->getUri();
  176. if ( $typedata->getSubject()->getUri() == $rdflistUri ) {
  177. $first = end( $this->m_children[$rdffirstUri] );
  178. $rest = end( $this->m_children[$rdfrestUri] );
  179. if ( $rest instanceof SMWExpData ) {
  180. $restlist = $rest->getCollection();
  181. if ( $restlist === false ) {
  182. return false;
  183. } else {
  184. array_unshift( $restlist, $first );
  185. return $restlist;
  186. }
  187. } elseif ( ( $rest instanceof SMWExpResource ) &&
  188. ( $rest->getUri() == $rdfnilUri ) ) {
  189. return array( $first );
  190. } else {
  191. return false;
  192. }
  193. } else {
  194. return false;
  195. }
  196. } elseif ( ( count( $this->m_children ) == 0 ) && ( $this->m_subject->getUri() == $rdfnilUri ) ) {
  197. return array();
  198. } else {
  199. return false;
  200. }
  201. }
  202. /**
  203. * Return an array of ternary arrays (subject predicate object) of
  204. * SMWExpElements that represents the flattened version of this data.
  205. *
  206. * @return array of array of SMWExpElement
  207. */
  208. public function getTripleList( SMWExpElement $subject = null ) {
  209. global $smwgBnodeCount;
  210. if ( !isset( $smwgBnodeCount ) ) {
  211. $smwgBnodeCount = 0;
  212. }
  213. if ( $subject == null ) {
  214. $subject = $this->m_subject;
  215. }
  216. $result = array();
  217. foreach ( $this->m_edges as $key => $edge ) {
  218. foreach ( $this->m_children[$key] as $childElement ) {
  219. if ( $childElement instanceof SMWExpData ) {
  220. $childSubject = $childElement->getSubject();
  221. } else {
  222. $childSubject = $childElement;
  223. }
  224. if ( ( $childSubject instanceof SMWExpResource ) &&
  225. ( $childSubject->isBlankNode() ) ) { // bnode, rename ID to avoid unifying bnodes of different contexts
  226. // TODO: should we really rename bnodes of the form "_id" here?
  227. $childSubject = new SMWExpResource( '_' . $smwgBnodeCount++, $childSubject->getDataItem() );
  228. }
  229. $result[] = array( $subject, $edge, $childSubject );
  230. if ( $childElement instanceof SMWExpData ) { // recursively add child's triples
  231. $result = array_merge( $result, $childElement->getTripleList( $childSubject ) );
  232. }
  233. }
  234. }
  235. return $result;
  236. }
  237. }