diff options
Diffstat (limited to 'SemanticMediaWiki/includes/export/SMW_Exp_Data.php')
-rw-r--r-- | SemanticMediaWiki/includes/export/SMW_Exp_Data.php | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/SemanticMediaWiki/includes/export/SMW_Exp_Data.php b/SemanticMediaWiki/includes/export/SMW_Exp_Data.php new file mode 100644 index 00000000..a430d490 --- /dev/null +++ b/SemanticMediaWiki/includes/export/SMW_Exp_Data.php @@ -0,0 +1,255 @@ +<?php +/** + * SMWExpData is a class representing semantic data that is ready for easy + * serialisation in OWL or RDF. + * + * @author Markus Krötzsch + * @file + * @ingroup SMW + */ + +/** + * SMWExpData is a data container for export-ready semantic content. It is + * organised as a tree-shaped data structure with one root subject and zero + * or more children connected with labelled edges to the root. Children are + * again SMWExpData objects, and edges are annotated with SMWExpNsElements + * specifying properties. + * @note We do not allow property element without namespace abbreviation + * here. Property aabbreviations are mandatory for some serialisations. + * + * @ingroup SMW + */ +class SMWExpData extends SMWExpElement { + /** + * The subject of the data that we store. + * @var SMWExpResource + */ + protected $m_subject; + /** + * Array mapping property URIs to arrays their values, given as + * SMWExpElement objects. + * @var array of array of SMWElement + */ + protected $m_children = array(); + /** + * Array mapping property URIs to arrays their SMWExpResource + * @var array of SMWExpResource + */ + protected $m_edges = array(); + + /** + * Constructor. $subject is the SMWExpResource for the + * subject about which this SMWExpData is. + */ + public function __construct( SMWExpResource $subject ) { + parent::__construct( $subject->getDataItem() ); + $this->m_subject = $subject; + } + + /** + * Turn an array of SMWExpElements into an RDF collection. + * + * @param $elements array of SMWExpElement + * @return SMWExpData + */ + public static function makeCollection( array $elements ) { + if ( count( $elements ) == 0 ) { + return new SMWExpData( SMWExporter::getSpecialNsResource( 'rdf', 'nil' ) ); + } else { + $rdftype = SMWExporter::getSpecialNsResource( 'rdf', 'type' ); + $rdffirst = SMWExporter::getSpecialNsResource( 'rdf', 'first' ); + $rdfrest = SMWExporter::getSpecialNsResource( 'rdf', 'rest' ); + $result = new SMWExpData( new SMWExpResource( '' ) ); // bnode + $result->addPropertyObjectValue( $rdftype, new SMWExpData( SMWExporter::getSpecialNsResource( 'rdf', 'List' ) ) ); + $result->addPropertyObjectValue( $rdffirst, array_shift( $elements ) ); + $result->addPropertyObjectValue( $rdfrest, SMWExpData::makeCollection( $elements ) ); + return $result; + } + } + + /** + * Return subject to which the stored semantic annotation refer to. + * + * @return SMWExpResource + */ + public function getSubject() { + return $this->m_subject; + } + + /** + * Store a value for a property identified by its title object. No + * duplicate elimination as this is usually done in SMWSemanticData + * already (which is typically used to generate this object). + * + * @param SMWExpNsResource $property + * @param SMWExpData $child + */ + public function addPropertyObjectValue( SMWExpNsResource $property, SMWExpElement $child ) { + if ( !array_key_exists( $property->getUri(), $this->m_edges ) ) { + $this->m_children[$property->getUri()] = array(); + $this->m_edges[$property->getUri()] = $property; + } + $this->m_children[$property->getUri()][] = $child; + } + + /** + * Return the list of SMWExpResource objects for all properties for + * which some values have been given. + * + * @return array of SMWExpResource + */ + public function getProperties() { + return $this->m_edges; + } + + /** + * Return the list of SMWExpElement values associated to some property + * (element). + * + * @return array of SMWExpElement + */ + public function getValues( SMWExpResource $property ) { + if ( array_key_exists( $property->getUri(), $this->m_children ) ) { + return $this->m_children[$property->getUri()]; + } else { + return array(); + } + } + + /** + * Return the list of SMWExpData values associated to some property that is + * specifed by a standard namespace id and local name. + * + * @param $namespaceId string idetifying a known special namespace (e.g. "rdf") + * @param $localName string of local name (e.g. "type") + * @return array of SMWExpData + */ + public function getSpecialValues( $namespaceId, $localName ) { + $pe = SMWExporter::getSpecialNsResource( $namespaceId, $localName ); + return $this->getValues( $pe ); + } + + /** + * This function finds the main type (class) element of the subject + * based on the current property assignments. It returns this type + * element (SMWExpElement) and removes the according type assignement + * from the data. If no type is assigned, the element for rdf:Resource + * is returned. + * + * @note Under all normal conditions, the result will be an + * SMWExpResource. + * + * @return SMWExpElement + */ + public function extractMainType() { + $pe = SMWExporter::getSpecialNsResource( 'rdf', 'type' ); + if ( array_key_exists( $pe->getUri(), $this->m_children ) ) { + $result = array_shift( $this->m_children[$pe->getUri()] ); + if ( count( $this->m_children[$pe->getUri()] ) == 0 ) { + unset( $this->m_edges[$pe->getUri()] ); + unset( $this->m_children[$pe->getUri()] ); + } + return ( $result instanceof SMWExpData ) ? $result->getSubject() : $result; + } else { + return SMWExporter::getSpecialNsResource( 'rdf', 'Resource' ); + } + } + + /** + * Check if this element encodes an RDF list, and if yes return an + * array of SMWExpElements corresponding to the collection elements in + * the specified order. Otherwise return false. + * The method only returns lists that can be encoded using + * parseType="Collection" in RDF/XML, i.e. only lists of non-literal + * resources. + * + * @return mixed array of SMWExpElement (but not SMWExpLiteral) or false + */ + public function getCollection() { + $rdftypeUri = SMWExporter::getSpecialNsResource( 'rdf', 'type' )->getUri(); + $rdffirstUri = SMWExporter::getSpecialNsResource( 'rdf', 'first' )->getUri(); + $rdfrestUri = SMWExporter::getSpecialNsResource( 'rdf', 'rest' )->getUri(); + $rdfnilUri = SMWExporter::getSpecialNsResource( 'rdf', 'nil' )->getUri(); + // first check if we are basically an RDF List: + if ( ( $this->m_subject->isBlankNode() ) && + ( count( $this->m_children ) == 3 ) && + ( array_key_exists( $rdftypeUri, $this->m_children ) ) && + ( count( $this->m_children[$rdftypeUri] ) == 1 ) && + ( array_key_exists( $rdffirstUri, $this->m_children ) ) && + ( count( $this->m_children[$rdffirstUri] ) == 1 ) && + !( end( $this->m_children[$rdffirstUri] ) instanceof SMWExpLiteral ) && + // (parseType collection in RDF not possible with literals :-/) + ( array_key_exists( $rdfrestUri, $this->m_children ) ) && + ( count( $this->m_children[$rdfrestUri] ) == 1 ) ) { + $typedata = end( $this->m_children[$rdftypeUri] ); + $rdflistUri = SMWExporter::getSpecialNsResource( 'rdf', 'List' )->getUri(); + if ( $typedata->getSubject()->getUri() == $rdflistUri ) { + $first = end( $this->m_children[$rdffirstUri] ); + $rest = end( $this->m_children[$rdfrestUri] ); + if ( $rest instanceof SMWExpData ) { + $restlist = $rest->getCollection(); + if ( $restlist === false ) { + return false; + } else { + array_unshift( $restlist, $first ); + return $restlist; + } + } elseif ( ( $rest instanceof SMWExpResource ) && + ( $rest->getUri() == $rdfnilUri ) ) { + return array( $first ); + } else { + return false; + } + } else { + return false; + } + } elseif ( ( count( $this->m_children ) == 0 ) && ( $this->m_subject->getUri() == $rdfnilUri ) ) { + return array(); + } else { + return false; + } + } + + /** + * Return an array of ternary arrays (subject predicate object) of + * SMWExpElements that represents the flattened version of this data. + * + * @return array of array of SMWExpElement + */ + public function getTripleList( SMWExpElement $subject = null ) { + global $smwgBnodeCount; + if ( !isset( $smwgBnodeCount ) ) { + $smwgBnodeCount = 0; + } + + if ( $subject == null ) { + $subject = $this->m_subject; + } + + $result = array(); + + foreach ( $this->m_edges as $key => $edge ) { + foreach ( $this->m_children[$key] as $childElement ) { + if ( $childElement instanceof SMWExpData ) { + $childSubject = $childElement->getSubject(); + } else { + $childSubject = $childElement; + } + + if ( ( $childSubject instanceof SMWExpResource ) && + ( $childSubject->isBlankNode() ) ) { // bnode, rename ID to avoid unifying bnodes of different contexts + // TODO: should we really rename bnodes of the form "_id" here? + $childSubject = new SMWExpResource( '_' . $smwgBnodeCount++, $childSubject->getDataItem() ); + } + + $result[] = array( $subject, $edge, $childSubject ); + if ( $childElement instanceof SMWExpData ) { // recursively add child's triples + $result = array_merge( $result, $childElement->getTripleList( $childSubject ) ); + } + } + } + + return $result; + } + +} |