r79731 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r79730‎ | r79731 | r79732 >
Date:16:55, 6 January 2011
Author:mkroetzsch
Status:deferred
Tags:
Comment:
Further modularized export serialisation code to introduce a new serialization syntax: Turtle. Extended export special page to accept parameter "format=turtle" to select this syntax. The main purpose of this code though is to facilitate future RDF store bindings since these stores use SPARQL as an exchange language, and SPARQL is based on Turtle.
Modified paths:
  • /trunk/extensions/SemanticMediaWiki/includes/SMW_Setup.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/export/SMW_ExportController.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/export/SMW_Exporter.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_RDFXML.php (added) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_Turtle.php (added) (history)
  • /trunk/extensions/SemanticMediaWiki/specials/Export/SMW_SpecialOWLExport.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticMediaWiki/specials/Export/SMW_SpecialOWLExport.php
@@ -104,16 +104,24 @@
105105 */
106106 protected function startRDFExport() {
107107 global $wgOut, $wgRequest;
 108+ $format = $wgRequest->getText( 'format' );
 109+ if ( $format == '' ) $format = $wgRequest->getVal( 'format' );
108110 $wgOut->disable();
109111 ob_start();
110 - // Only use rdf+xml mimetype if explicitly requested
111 - // TODO: should the see also links in the exported RDF then have this parameter as well?
112 - if ( $wgRequest->getVal( 'xmlmime' ) == 'rdf' ) {
113 - header( "Content-type: application/rdf+xml; charset=UTF-8" );
114 - } else {
115 - header( "Content-type: application/xml; charset=UTF-8" );
 112+ if ( $format == 'turtle' ) {
 113+ $mimetype = 'application/x-turtle'; // may change to 'text/turtle' at some time, watch Turtle development
 114+ $serializer = new SMWTurtleSerializer();
 115+ } else { // rdfxml as default
 116+ // Only use rdf+xml mimetype if explicitly requested (browsers do
 117+ // not support it by default).
 118+ // We do not add this parameter to RDF links within the export
 119+ // though; it is only meant to help some tools to see that HTML
 120+ // included resources are RDF (from there on they should be fine).
 121+ $mimetype = ( $wgRequest->getVal( 'xmlmime' ) == 'rdf' ) ? 'application/rdf+xml' : 'application/xml';
 122+ $serializer = new SMWRDFXMLSerializer();
116123 }
117 - $this->export_controller = new SMWExportController( new SMWSerializer() );
 124+ header( "Content-type: $mimetype; charset=UTF-8" );
 125+ $this->export_controller = new SMWExportController( $serializer );
118126 }
119127
120128 /**
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_ExportController.php
@@ -354,24 +354,6 @@
355355 flush();
356356 }
357357 }
358 -
359 - /**
360 - * Create an SMWExpData container that encodes the ontology header for an
361 - * SMW exported OWL file.
362 - *
363 - * @param string $ontologyuri specifying the URI of the ontology, possibly
364 - * empty
365 - */
366 - protected function getOntologyExpData( $ontologyuri ) {
367 - $data = new SMWExpData( new SMWExpResource( $ontologyuri ) );
368 - $ed = new SMWExpData( SMWExporter::getSpecialElement( 'owl', 'Ontology' ) );
369 - $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'rdf', 'type' ), $ed );
370 - $ed = new SMWExpData( new SMWExpLiteral( date( DATE_W3C ), null, 'http://www.w3.org/2001/XMLSchema#dateTime' ) );
371 - $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'swivt', 'creationDate' ), $ed );
372 - $ed = new SMWExpData( new SMWExpResource( 'http://semantic-mediawiki.org/swivt/1.0' ) );
373 - $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'owl', 'imports' ), $ed );
374 - return $data;
375 - }
376358
377359 /**
378360 * This function prints all selected pages, specified as an array of page
@@ -411,21 +393,21 @@
412394 $this->element_queue[$st->getHash()] = $st;
413395 }
414396
415 - $this->serializer->serializeHeader();
 397+ $this->serializer->startSerialization();
416398
417399 if ( count( $pages ) == 1 ) { // ensure that ontologies that are retrieved as linked data are not confused with their subject!
418400 $ontologyuri = SMWExporter::expandURI( '&export;' ) . '/' . urlencode( end( $pages ) );
419401 } else { // use empty URI, i.e. "location" as URI otherwise
420402 $ontologyuri = '';
421403 }
422 - $this->serializer->serializeExpData( $this->getOntologyExpData( $ontologyuri ) );
 404+ $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( $ontologyuri ) );
423405
424406 while ( count( $this->element_queue ) > 0 ) {
425407 $this->serializeSmallTitle( reset( $this->element_queue ) );
426408 $this->flush();
427409 $linkCache->clear(); // avoid potential memory leak
428410 }
429 - $this->serializer->serializeFooter();
 411+ $this->serializer->finishSerialization();
430412 $this->flush( true );
431413
432414 wfProfileOut( "RDF::PrintPages" );
@@ -450,8 +432,8 @@
451433 $this->delay_flush = 10;
452434 if ( !$this->prepareSerialization( $outfile ) ) return;
453435
454 - $this->serializer->serializeHeader();
455 - $this->serializer->serializeExpData( $this->getOntologyExpData( '' ) );
 436+ $this->serializer->startSerialization();
 437+ $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( '' ) );
456438
457439 $end = $db->selectField( 'page', 'max(page_id)', false, $outfile );
458440 $a_count = 0; $d_count = 0; // DEBUG
@@ -493,7 +475,7 @@
494476 $linkCache->clear();
495477 }
496478
497 - $this->serializer->serializeFooter();
 479+ $this->serializer->finishSerialization();
498480 $this->flush( true );
499481 }
500482
@@ -514,8 +496,8 @@
515497 $this->delay_flush = 35; // don't do intermediate flushes with default parameters
516498 $linkCache = LinkCache::singleton();
517499
518 - $this->serializer->serializeHeader();
519 - $this->serializer->serializeExpData( $this->getOntologyExpData( '' ) );
 500+ $this->serializer->startSerialization();
 501+ $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( '' ) );
520502
521503 $query = '';
522504 foreach ( $smwgNamespacesWithSemanticLinks as $ns => $enabled ) {
@@ -554,7 +536,7 @@
555537 $this->serializer->serializeExpData( $data );
556538 }
557539
558 - $this->serializer->serializeFooter();
 540+ $this->serializer->finishSerialization();
559541 $this->flush( true );
560542
561543 wfProfileOut( "RDF::PrintPageList" );
@@ -610,8 +592,8 @@
611593 $ed = new SMWExpData( new SMWExpLiteral( SiteStats::admins(), null, 'http://www.w3.org/2001/XMLSchema#int' ) );
612594 $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'swivt', 'adminCount' ), $ed );
613595
614 - $this->serializer->serializeHeader();
615 - $this->serializer->serializeExpData( $this->getOntologyExpData( '' ) );
 596+ $this->serializer->startSerialization();
 597+ $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( '' ) );
616598 $this->serializer->serializeExpData( $data );
617599
618600 // link to list of existing pages:
@@ -627,7 +609,7 @@
628610 $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'rdfs', 'isDefinedBy' ), $ed );
629611 $this->serializer->serializeExpData( $data );
630612
631 - $this->serializer->serializeFooter();
 613+ $this->serializer->finishSerialization();
632614 $this->flush( true );
633615
634616 wfProfileOut( "RDF::PrintWikiInfo" );
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_RDFXML.php
@@ -0,0 +1,199 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the SMWRDFXMLSerializer class that provides basic functions for
 6+ * serialising OWL data in RDF/XML syntax.
 7+ *
 8+ * @file SMW_Serializer.php
 9+ * @ingroup SMW
 10+ *
 11+ * @author Markus Krötzsch
 12+ */
 13+
 14+/**
 15+ * Class for serializing exported data (encoded as SMWExpData object) in
 16+ * RDF/XML.
 17+ *
 18+ * @ingroup SMW
 19+ */
 20+class SMWRDFXMLSerializer extends SMWSerializer{
 21+ /**
 22+ * True if the $pre_ns_buffer contains the beginning of a namespace
 23+ * declaration block to which further declarations for the current
 24+ * context can be appended.
 25+ */
 26+ protected $namespace_block_started;
 27+ /**
 28+ * True if the namespaces that are added at the current serialization stage
 29+ * become global, i.e. remain available for all later contexts. This is the
 30+ * case in RDF/XML only as long as the header has not been streamed to the
 31+ * client (reflected herein by calling flushContent()). Later, namespaces
 32+ * can only be added locally to individual elements, thus requiring them to
 33+ * be re-added multiple times if used in many elements.
 34+ */
 35+ protected $namespaces_are_global;
 36+
 37+ public function clear() {
 38+ parent::clear();
 39+ $this->namespaces_are_global = false;
 40+ $this->namespace_block_started = false;
 41+ }
 42+
 43+ protected function serializeHeader() {
 44+ $this->namespaces_are_global = true;
 45+ $this->namespace_block_started = true;
 46+ $this->pre_ns_buffer =
 47+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
 48+ "<!DOCTYPE rdf:RDF[\n" .
 49+ "\t<!ENTITY rdf " . $this->makeValueEntityString( SMWExporter::expandURI( '&rdf;' ) ) . ">\n" .
 50+ "\t<!ENTITY rdfs " . $this->makeValueEntityString( SMWExporter::expandURI( '&rdfs;' ) ) . ">\n" .
 51+ "\t<!ENTITY owl " . $this->makeValueEntityString( SMWExporter::expandURI( '&owl;' ) ) . ">\n" .
 52+ "\t<!ENTITY swivt " . $this->makeValueEntityString( SMWExporter::expandURI( '&swivt;' ) ) . ">\n" .
 53+ // A note on "wiki": this namespace is crucial as a fallback when it would be illegal to start e.g. with a number.
 54+ // In this case, one can always use wiki:... followed by "_" and possibly some namespace, since _ is legal as a first character.
 55+ "\t<!ENTITY wiki " . $this->makeValueEntityString( SMWExporter::expandURI( '&wiki;' ) ) . ">\n" .
 56+ "\t<!ENTITY property " . $this->makeValueEntityString( SMWExporter::expandURI( '&property;' ) ) . ">\n" .
 57+ "\t<!ENTITY wikiurl " . $this->makeValueEntityString( SMWExporter::expandURI( '&wikiurl;' ) ) . ">\n" .
 58+ "]>\n\n" .
 59+ "<rdf:RDF\n" .
 60+ "\txmlns:rdf=\"&rdf;\"\n" .
 61+ "\txmlns:rdfs=\"&rdfs;\"\n" .
 62+ "\txmlns:owl =\"&owl;\"\n" .
 63+ "\txmlns:swivt=\"&swivt;\"\n" .
 64+ "\txmlns:wiki=\"&wiki;\"\n" .
 65+ "\txmlns:property=\"&property;\"";
 66+ $this->global_namespaces = array( 'rdf' => true, 'rdfs' => true, 'owl' => true, 'swivt' => true, 'wiki' => true, 'property' => true );
 67+ $this->post_ns_buffer .= ">\n\n";
 68+ }
 69+
 70+ protected function serializeFooter() {
 71+ $this->post_ns_buffer .= "\t<!-- Created by Semantic MediaWiki, http://semantic-mediawiki.org/ -->\n";
 72+ $this->post_ns_buffer .= '</rdf:RDF>';
 73+ }
 74+
 75+ public function serializeDeclaration( $uri, $typename ) {
 76+ $this->post_ns_buffer .= "\t<$typename rdf:about=\"$uri\" />\n";
 77+ }
 78+
 79+ public function serializeExpData( SMWExpData $data ) {
 80+ $this->serializeNestedExpData( $data, '' );
 81+ $this->serializeNamespaces();
 82+ if ( !$this->namespaces_are_global ) {
 83+ $this->pre_ns_buffer .= $this->post_ns_buffer;
 84+ $this->post_ns_buffer = '';
 85+ $this->namespace_block_started = false;
 86+ }
 87+ }
 88+
 89+ public function flushContent() {
 90+ $result = parent::flushContent();
 91+ $this->namespaces_are_global = false; // must not be done before calling the parent method (which may declare namespaces)
 92+ $this->namespace_block_started = false;
 93+ return $result;
 94+ }
 95+
 96+ protected function serializeNamespace( $shortname, $uri ) {
 97+ if ( $this->namespaces_are_global ) {
 98+ $this->global_namespaces[$shortname] = true;
 99+ $this->pre_ns_buffer .= "\n\t";
 100+ } else {
 101+ $this->pre_ns_buffer .= ' ';
 102+ }
 103+ $this->pre_ns_buffer .= "xmlns:$shortname=\"$uri\"";
 104+ }
 105+
 106+ /**
 107+ * Serialize the given SMWExpData object, possibly recursively with
 108+ * increased indentation.
 109+ *
 110+ * @param $data SMWExpData containing the data to be serialised.
 111+ * @param $indent string specifying a prefix for indentation (usually a sequence of tabs)
 112+ */
 113+ protected function serializeNestedExpData( SMWExpData $data, $indent ) {
 114+ $this->recordDeclarationTypes( $data );
 115+
 116+ $type = $data->extractMainType()->getQName();
 117+ if ( !$this->namespace_block_started ) { // start new ns block
 118+ $this->pre_ns_buffer .= "\t$indent<$type";
 119+ $this->namespace_block_started = true;
 120+ } else { // continue running block
 121+ $this->post_ns_buffer .= "\t$indent<$type";
 122+ }
 123+
 124+ if ( ( $data->getSubject() instanceof SMWExpLiteral ) ||
 125+ ( $data->getSubject() instanceof SMWExpResource ) ) {
 126+ $this->post_ns_buffer .= ' rdf:about="' . $data->getSubject()->getName() . '"';
 127+ } // else: blank node, no "rdf:about"
 128+
 129+ if ( count( $data->getProperties() ) == 0 ) { // nothing else to export
 130+ $this->post_ns_buffer .= " />\n";
 131+ } else { // process data
 132+ $this->post_ns_buffer .= ">\n";
 133+
 134+ foreach ( $data->getProperties() as $property ) {
 135+ $prop_decl_queued = false;
 136+ $class_type_prop = $this->isOWLClassTypeProperty( $property );
 137+
 138+ foreach ( $data->getValues( $property ) as $value ) {
 139+ $this->post_ns_buffer .= "\t\t$indent<" . $property->getQName();
 140+ $this->requireNamespace( $property->getNamespaceID(), $property->getNamespace() );
 141+ $object = $value->getSubject();
 142+
 143+ if ( $object instanceof SMWExpLiteral ) {
 144+ $prop_decl_type = SMW_SERIALIZER_DECL_APROP;
 145+ if ( $object->getDatatype() != '' ) {
 146+ $this->post_ns_buffer .= ' rdf:datatype="' . $object->getDatatype() . '"';
 147+ }
 148+ $this->post_ns_buffer .= '>' .
 149+ str_replace( array( '&', '>', '<' ), array( '&amp;', '&gt;', '&lt;' ), $object->getName() ) .
 150+ '</' . $property->getQName() . ">\n";
 151+ } else { // resource (maybe blank node), could have subdescriptions
 152+ $prop_decl_type = SMW_SERIALIZER_DECL_OPROP;
 153+ $collection = $value->getCollection();
 154+ if ( $collection !== false ) { // RDF-style collection (list)
 155+ $this->post_ns_buffer .= " rdf:parseType=\"Collection\">\n";
 156+ foreach ( $collection as $subvalue ) {
 157+ $this->serializeNestedExpData( $subvalue, $indent . "\t\t" );
 158+ if ( $class_type_prop ) {
 159+ $this->requireDeclaration( $subvalue, SMW_SERIALIZER_DECL_CLASS );
 160+ }
 161+ }
 162+ $this->post_ns_buffer .= "\t\t$indent</" . $property->getQName() . ">\n";
 163+ } else {
 164+ if ( $class_type_prop ) {
 165+ $this->requireDeclaration( $object, SMW_SERIALIZER_DECL_CLASS );
 166+ }
 167+ if ( count( $value->getProperties() ) > 0 ) { // resource with data: serialise
 168+ $this->post_ns_buffer .= ">\n";
 169+ $this->serializeNestedExpData( $value, $indent . "\t\t" );
 170+ $this->post_ns_buffer .= "\t\t$indent</" . $property->getQName() . ">\n";
 171+ } else { // resource without data
 172+ if ( !$object->isBlankNode() ) {
 173+ $this->post_ns_buffer .= ' rdf:resource="' . $object->getName() . '"';
 174+ }
 175+ $this->post_ns_buffer .= "/>\n";
 176+ }
 177+ }
 178+ }
 179+
 180+ if ( !$prop_decl_queued ) {
 181+ $this->requireDeclaration( $property, $prop_decl_type );
 182+ $prop_decl_queued = true;
 183+ }
 184+ }
 185+ }
 186+ $this->post_ns_buffer .= "\t$indent</" . $type . ">\n";
 187+ }
 188+ }
 189+
 190+ /**
 191+ * Escape a string in the special form that is required for values in
 192+ * DTD entity declarations in XML. Namely, this require the percent sign
 193+ * to be replaced.
 194+ * @param string $string to be escaped
 195+ */
 196+ protected function makeValueEntityString( $string ) {
 197+ return "'" . str_replace( '%','&#37;',$string ) . "'";
 198+ }
 199+
 200+}
Property changes on: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_RDFXML.php
___________________________________________________________________
Added: svn:eol-style
1201 + native
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Exporter.php
@@ -56,36 +56,52 @@
5757 static public function makeExportData( /*SMWSemanticData*/ $semdata, $modifier = '' ) {
5858 SMWExporter::initBaseURIs();
5959 $subject = $semdata->getSubject();
 60+ if ( $subject->getNamespace() == SMW_NS_PROPERTY ) {
 61+ $types = $semdata->getPropertyValues( SMWPropertyValue::makeProperty( '_TYPE' ) );
 62+ } else {
 63+ $types = array();
 64+ }
 65+ $result = SMWExporter::makeExportDataForSubject( $subject, $modifier, end( $types ) );
 66+ foreach ( $semdata->getProperties() as $property ) {
 67+ SMWExporter::addPropertyValues( $property, $semdata->getPropertyValues( $property ), $result );
 68+ }
 69+ return $result;
 70+ }
 71+
 72+ /**
 73+ * Make an SMWExpData object for the given page, and include the basic
 74+ * properties about this subject that are not directly represented by
 75+ * SMW property values. If given, the string $modifier is used as a
 76+ * modifier to the URI of the subject (e.g. a unit for properties).
 77+ * See also the documentation of makeExportData(). The optional parameter
 78+ * $typevalueforproperty can be used to pass a particular SMWTypesValue
 79+ * object that is used for determining the OWL type for property pages.
 80+ *
 81+ * @param SMWWikiPageValue $subject
 82+ * @param string $modifier
 83+ * @param mixed $typesvalueforproperty either an SMWTypesValue or null
 84+ */
 85+ static public function makeExportDataForSubject( SMWWikiPageValue $subject, $modifier = '', $typesvalueforproperty = null ) {
6086 $result = $subject->getExportData();
61 -
62 - // first set some general parameters for export
63 - $category_pe = null;
64 - $subprop_pe = null;
6587 switch ( $subject->getNamespace() ) {
6688 case NS_CATEGORY: case SMW_NS_CONCEPT:
67 - $category_pe = SMWExporter::getSpecialElement( 'rdfs', 'subClassOf' );
68 - $equality_pe = SMWExporter::getSpecialElement( 'owl', 'equivalentClass' );
6989 $maintype_pe = SMWExporter::getSpecialElement( 'owl', 'Class' );
7090 $label = $subject->getText();
7191 break;
7292 case SMW_NS_PROPERTY:
73 - $category_pe = SMWExporter::getSpecialElement( 'rdf', 'type' );
74 - $subprop_pe = SMWExporter::getSpecialElement( 'rdfs', 'subPropertyOf' );
75 - $equality_pe = SMWExporter::getSpecialElement( 'owl', 'equivalentProperty' );
76 - $types = $semdata->getPropertyValues( SMWPropertyValue::makeProperty( '_TYPE' ) );
77 - $maintype_pe = SMWExporter::getSpecialElement( 'owl', SMWExporter::getOWLPropertyType( end( $types ) ) );
 93+ if ( $typesvalueforproperty == null ) {
 94+ $types = smwfGetStore()->getPropertyValues( $subject, SMWPropertyValue::makeProperty( '_TYPE' ) );
 95+ $typesvalueforproperty = end( $types );
 96+ }
 97+ $maintype_pe = SMWExporter::getSpecialElement( 'owl', SMWExporter::getOWLPropertyType( $typesvalueforproperty ) );
7898 $label = $subject->getText();
7999 break;
80100 default:
81 - $category_pe = SMWExporter::getSpecialElement( 'rdf', 'type' );
82 - $equality_pe = SMWExporter::getSpecialElement( 'owl', 'sameAs' );
 101+ $label = $subject->getWikiValue();
83102 $maintype_pe = SMWExporter::getSpecialElement( 'swivt', 'Subject' );
84 - $label = $subject->getWikiValue();
85103 }
86 -
87 - // export standard properties
88104 if ( $modifier != '' ) {
89 - $modifier = smwfHTMLtoUTF8( $modifier ); ///TODO: check if this is needed anymore
 105+ $modifier = smwfHTMLtoUTF8( $modifier ); ///TODO: check if this is still needed
90106 $label .= ' (' . $modifier . ')';
91107 }
92108 $ed = new SMWExpData( new SMWExpLiteral( $label ) );
@@ -106,75 +122,94 @@
107123 }
108124 $result->setSubject( $result->getSubject()->makeVariant( $modifier ) );
109125 }
110 -
111 - // export properties based on stored data
112 - foreach ( $semdata->getProperties() as $key => $property ) {
113 - if ( $property->isUserDefined() ) {
114 - $pe = SMWExporter::getResourceElement( $property );
115 - foreach ( $semdata->getPropertyValues( $property ) as $dv ) {
116 - $ed = $dv->getExportData();
117 - if ( $ed !== null ) {
118 - $pem = ( $dv->getUnit() != false ) ? $pe->makeVariant( $dv->getUnit() ):$pe;
119 - $result->addPropertyObjectValue( $pem, $ed );
 126+ return $result;
 127+ }
 128+
 129+ /**
 130+ * Extend a given SMWExpData element by adding export data for the
 131+ * specified property values.
 132+ *
 133+ * @param SMWPropertyValue $property
 134+ * @param array $values of SMWDatavalue object for the given property
 135+ * @param SMWExpData $data to add the data to
 136+ */
 137+ static public function addPropertyValues(SMWPropertyValue $property, $values, SMWExpData &$data) {
 138+ if ( $property->isUserDefined() ) {
 139+ $pe = SMWExporter::getResourceElement( $property );
 140+ foreach ( $values as $dv ) {
 141+ $ed = $dv->getExportData();
 142+ if ( $ed !== null ) {
 143+ if ( ( $dv instanceof SMWNumberValue ) && ( $dv->getUnit() != '' ) ) {
 144+ $pem = $pe->makeVariant( $dv->getUnit() );
 145+ } else {
 146+ $pem = $pe;
120147 }
 148+ $data->addPropertyObjectValue( $pem, $ed );
121149 }
122 - } else { // pre-defined property
123 - $pe = null;
124 - $cat_only = false; // basic namespace checking for equivalent categories
125 - switch ( $property->getPropertyID() ) {
126 - case '_INST': ///TODO: distinguish instanceof and subclassof
127 - $pe = $category_pe;
128 - break;
129 - case '_CONC':
 150+ }
 151+ } else { // pre-defined property, only exported if known
 152+ $subject = $data->getSubject()->getDatavalue();
 153+ if ( $subject == null ) return; // subject datavalue (wikipage) required for treating special properties properly
 154+ switch ( $subject->getNamespace() ) {
 155+ case NS_CATEGORY: case SMW_NS_CONCEPT:
 156+ $category_pe = SMWExporter::getSpecialElement( 'rdfs', 'subClassOf' );
 157+ $subprop_pe = null;
 158+ $equality_pe = SMWExporter::getSpecialElement( 'owl', 'equivalentClass' );
 159+ break;
 160+ case SMW_NS_PROPERTY:
 161+ $category_pe = SMWExporter::getSpecialElement( 'rdf', 'type' );
 162+ $subprop_pe = SMWExporter::getSpecialElement( 'rdfs', 'subPropertyOf' );
 163+ $equality_pe = SMWExporter::getSpecialElement( 'owl', 'equivalentProperty' );
 164+ break;
 165+ default:
 166+ $category_pe = SMWExporter::getSpecialElement( 'rdf', 'type' );
 167+ $subprop_pe = null;
 168+ $equality_pe = SMWExporter::getSpecialElement( 'owl', 'sameAs' );
 169+ }
 170+ $pe = null;
 171+ $cat_only = false; // basic namespace checking for equivalent categories
 172+ switch ( $property->getPropertyID() ) {
 173+ ///TODO: distinguish instanceof and subclassof in the _INST case
 174+ case '_INST': $pe = $category_pe; break;
 175+ case '_CONC': $pe = $equality_pe; break;
 176+ case '_URI': $pe = $equality_pe; break;
 177+ case '_SUBP': $pe = $subprop_pe; break;
 178+ case '_MDAT':
 179+ $pe = SMWExporter::getSpecialElement( 'swivt', 'wikiPageModificationDate' );
 180+ break;
 181+ case '_REDI': /// TODO: currently no check for avoiding OWL DL illegal redirects is done
 182+ if ( $subject->getNamespace() == SMW_NS_PROPERTY ) {
 183+ $pe = null; // checking the typing here is too cumbersome, smart stores will smush the properties anyway, and the others will not handle them equivalently
 184+ } else {
130185 $pe = $equality_pe;
131 - break;
132 - case '_URI':
133 - $pe = $equality_pe;
134 - break;
135 - case '_SUBP':
136 - $pe = $subprop_pe;
137 - break;
138 - case '_MDAT':
139 - $pe = SMWExporter::getSpecialElement( 'swivt', 'wikiPageModificationDate' );
140 - break;
141 - case '_REDI': /// TODO: currently no check for avoiding OWL DL illegal redirects is done
142 - if ( $subject->getNamespace() == SMW_NS_PROPERTY ) {
143 - $pe = null; // checking the typing here is too cumbersome, smart stores will smush the properties anyway, and the others will not handle them equivalently
144 - } else {
145 - $pe = $equality_pe;
146 - $cat_only = ( $subject->getNamespace() == NS_CATEGORY );
147 - }
148 - break;
 186+ $cat_only = ( $subject->getNamespace() == NS_CATEGORY );
 187+ }
 188+ break;
 189+ }
 190+ if ( $pe === null ) return; // unknown special property, not exported
 191+ foreach ( $values as $dv ) {
 192+ if ( $cat_only ) {
 193+ if ( !( $dv instanceof SMWWikiPageValue ) || ( $dv->getNamespace() != NS_CATEGORY ) ) {
 194+ continue;
 195+ }
149196 }
150 - if ( $pe !== null ) {
151 - foreach ( $semdata->getPropertyValues( $property ) as $dv ) {
152 - if ( $cat_only ) {
153 - if ( !( $dv instanceof SMWWikiPageValue ) || ( $dv->getNamespace() != NS_CATEGORY ) ) {
154 - continue;
155 - }
156 - }
157 - $ed = $dv->getExportData();
158 - if ( $ed !== null ) {
159 - if ( ( $property->getPropertyID() == '_CONC' ) &&
160 - ( $ed->getSubject()->getName() == '' ) ) {
161 - // equivalent to anonymous class -> simplify description
162 - foreach ( $ed->getProperties() as $subp ) {
163 - if ( $subp->getName() != SMWExporter::getSpecialElement( 'rdf', 'type' )->getName() ) {
164 - foreach ( $ed->getValues( $subp ) as $subval ) {
165 - $result->addPropertyObjectValue( $subp, $subval );
166 - }
167 - }
 197+ $ed = $dv->getExportData();
 198+ if ( $ed !== null ) {
 199+ if ( ( $property->getPropertyID() == '_CONC' ) && ( $ed->getSubject()->getName() == '' ) ) {
 200+ // equivalent to anonymous class -> simplify description
 201+ foreach ( $ed->getProperties() as $subp ) {
 202+ if ( $subp->getName() != SMWExporter::getSpecialElement( 'rdf', 'type' )->getName() ) {
 203+ foreach ( $ed->getValues( $subp ) as $subval ) {
 204+ $data->addPropertyObjectValue( $subp, $subval );
168205 }
169 - } else {
170 - $result->addPropertyObjectValue( $pe, $ed );
171206 }
172207 }
 208+ } else {
 209+ $data->addPropertyObjectValue( $pe, $ed );
173210 }
174211 }
175212 }
176213 }
177 -
178 - return $result;
179214 }
180215
181216 /**
@@ -298,4 +333,22 @@
299334 return $uri;
300335 }
301336
 337+ /**
 338+ * Create an SMWExpData container that encodes the ontology header for an
 339+ * SMW exported OWL file.
 340+ *
 341+ * @param string $ontologyuri specifying the URI of the ontology, possibly
 342+ * empty
 343+ */
 344+ static public function getOntologyExpData( $ontologyuri ) {
 345+ $data = new SMWExpData( new SMWExpResource( $ontologyuri ) );
 346+ $ed = new SMWExpData( SMWExporter::getSpecialElement( 'owl', 'Ontology' ) );
 347+ $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'rdf', 'type' ), $ed );
 348+ $ed = new SMWExpData( new SMWExpLiteral( date( DATE_W3C ), null, 'http://www.w3.org/2001/XMLSchema#dateTime' ) );
 349+ $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'swivt', 'creationDate' ), $ed );
 350+ $ed = new SMWExpData( new SMWExpResource( 'http://semantic-mediawiki.org/swivt/1.0' ) );
 351+ $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'owl', 'imports' ), $ed );
 352+ return $data;
 353+ }
 354+
302355 }
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_Turtle.php
@@ -0,0 +1,175 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the SMWTurtleSerializer class that provides basic functions for
 6+ * serialising OWL data in Turtle syntax.
 7+ *
 8+ * @file SMW_Serializer.php
 9+ * @ingroup SMW
 10+ *
 11+ * @author Markus Krötzsch
 12+ */
 13+
 14+/**
 15+ * Class for serializing exported data (encoded as SMWExpData object) in
 16+ * Turtle syntax.
 17+ *
 18+ * @ingroup SMW
 19+ */
 20+class SMWTurtleSerializer extends SMWSerializer{
 21+ /**
 22+ * Array of non-trivial sub-SMWExpData elements that cannot be nested while
 23+ * serializing some SMWExpData. The elements of the array are serialized
 24+ * later during the same serialization step (so this is not like another
 25+ * queue for declarations or the like; it just unfolds an SMWExpData
 26+ * object).
 27+ */
 28+ protected $subexpdata;
 29+
 30+ protected function serializeHeader() {
 31+ $this->pre_ns_buffer =
 32+ "@prefix rdf: <" . SMWExporter::expandURI( '&rdf;' ) . "> .\n" .
 33+ "@prefix rdfs: <" . SMWExporter::expandURI( '&rdfs;' ) . "> .\n" .
 34+ "@prefix owl: <" . SMWExporter::expandURI( '&owl;' ) . "> .\n" .
 35+ "@prefix swivt: <" . SMWExporter::expandURI( '&swivt;' ) . "> .\n" .
 36+ // A note on "wiki": this namespace is crucial as a fallback when it would be illegal to start e.g. with a number.
 37+ // In this case, one can always use wiki:... followed by "_" and possibly some namespace, since _ is legal as a first character.
 38+ "@prefix wiki: <" . SMWExporter::expandURI( '&wiki;' ) . "> .\n" .
 39+ "@prefix property: <" . SMWExporter::expandURI( '&property;' ) . "> .\n" .
 40+ "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" . // note that this XSD URI is hardcoded below (its unlikely to change, of course)
 41+ "@prefix wikiurl: <" . SMWExporter::expandURI( '&wikiurl;' ) . "> .\n";
 42+ $this->global_namespaces = array( 'rdf' => true, 'rdfs' => true, 'owl' => true, 'swivt' => true, 'wiki' => true, 'property' => true );
 43+ $this->post_ns_buffer = "\n";
 44+ }
 45+
 46+ protected function serializeFooter() {
 47+ $this->post_ns_buffer .= "\n# Created by Semantic MediaWiki, http://semantic-mediawiki.org/\n";
 48+ }
 49+
 50+ public function serializeDeclaration( $uri, $typename ) {
 51+ $this->post_ns_buffer .= "<" . SMWExporter::expandURI( $uri ) . "> rdf:type $typename .\n";
 52+ }
 53+
 54+ public function serializeExpData( SMWExpData $data ) {
 55+ $this->subexpdata = array( $data );
 56+ while ( count( $this->subexpdata ) > 0 ) {
 57+ $this->serializeNestedExpData( array_pop( $this->subexpdata ), '' );
 58+ }
 59+ $this->serializeNamespaces();
 60+
 61+ }
 62+
 63+ protected function serializeNamespace( $shortname, $uri ) {
 64+ $this->global_namespaces[$shortname] = true;
 65+ $this->pre_ns_buffer .= "@prefix $shortname: <$uri> .\n";
 66+ }
 67+
 68+ /**
 69+ * Serialize the given SMWExpData object, possibly recursively with
 70+ * increased indentation.
 71+ *
 72+ * @param $data SMWExpData containing the data to be serialised.
 73+ * @param $indent string specifying a prefix for indentation (usually a sequence of tabs)
 74+ */
 75+ protected function serializeNestedExpData( SMWExpData $data, $indent ) {
 76+ if ( count( $data->getProperties() ) == 0 ) return; // nothing to export
 77+ $this->recordDeclarationTypes( $data );
 78+
 79+ $bnode = false;
 80+ $this->post_ns_buffer .= $indent;
 81+ if ( $data->getSubject() instanceof SMWExpLiteral ) {
 82+ $this->serializeExpLiteral( $data->getSubject() );
 83+ } elseif ( ( $data->getSubject() instanceof SMWExpResource ) && ( !$data->getSubject()->isBlankNode() ) ) {
 84+ $this->serializeExpResource( $data->getSubject() );
 85+ } else { // blank node
 86+ $bnode = true;
 87+ $this->post_ns_buffer .= "[";
 88+ }
 89+
 90+ if ( ( $indent != '' ) && ( !$bnode ) ) { // called to generate a nested descripion; but Turtle cannot nest non-bnode descriptions, do this later
 91+ $this->subexpdata[] = $data;
 92+ return;
 93+ } elseif ( !$bnode ) {
 94+ $this->post_ns_buffer .= "\n ";
 95+ }
 96+
 97+ $firstproperty = true;
 98+ foreach ( $data->getProperties() as $property ) {
 99+ $this->post_ns_buffer .= $firstproperty ? "\t" : " ;\n $indent\t";
 100+ $firstproperty = false;
 101+ $prop_decl_queued = false;
 102+ $class_type_prop = $this->isOWLClassTypeProperty( $property );
 103+ $this->serializeExpResource( $property );
 104+ $firstvalue = true;
 105+
 106+ foreach ( $data->getValues( $property ) as $value ) {
 107+ $this->post_ns_buffer .= $firstvalue ? ' ' : ' , ';
 108+ $firstvalue = false;
 109+
 110+ $this->requireNamespace( $property->getNamespaceID(), $property->getNamespace() );
 111+ $object = $value->getSubject();
 112+
 113+ if ( $object instanceof SMWExpLiteral ) {
 114+ $prop_decl_type = SMW_SERIALIZER_DECL_APROP;
 115+ $this->serializeExpLiteral( $object );
 116+ } else { // resource (maybe blank node), could have subdescriptions
 117+ $prop_decl_type = SMW_SERIALIZER_DECL_OPROP;
 118+ $collection = $value->getCollection();
 119+ if ( $collection !== false ) { // RDF-style collection (list)
 120+ $this->post_ns_buffer .= "( ";
 121+ foreach ( $collection as $subvalue ) {
 122+ $this->serializeNestedExpData( $subvalue, $indent . "\t\t" );
 123+ if ( $class_type_prop ) {
 124+ $this->requireDeclaration( $subvalue, SMW_SERIALIZER_DECL_CLASS );
 125+ }
 126+ }
 127+ $this->post_ns_buffer .= " )";
 128+ } else {
 129+ if ( $class_type_prop ) {
 130+ $this->requireDeclaration( $object, SMW_SERIALIZER_DECL_CLASS );
 131+ }
 132+ if ( count( $value->getProperties() ) > 0 ) { // resource with data: serialise
 133+ $this->post_ns_buffer .= "\n";
 134+ $this->serializeNestedExpData( $value, $indent . "\t\t" );
 135+ } else { // resource without data: may need to be queued
 136+ $this->serializeExpResource( $object );
 137+ }
 138+ }
 139+ }
 140+
 141+ if ( !$prop_decl_queued ) {
 142+ $this->requireDeclaration( $property, $prop_decl_type );
 143+ $prop_decl_queued = true;
 144+ }
 145+ }
 146+ }
 147+ $this->post_ns_buffer .= ( $bnode ? " ]" : " ." ) . ( $indent == '' ? "\n\n" : '' );
 148+ }
 149+
 150+ protected function serializeExpLiteral( SMWExpLiteral $element ) {
 151+ $this->post_ns_buffer .= '"' . str_replace( array( '\\', "\n", '"' ), array( '\\\\', "\\n", '\"' ), $element->getName() ) . '"';
 152+ $dt = $element->getDatatype();
 153+ if ( ( $dt != '' ) && ( $dt != 'http://www.w3.org/2001/XMLSchema#string' ) ) {
 154+ $count = 0;
 155+ $newdt = str_replace( 'http://www.w3.org/2001/XMLSchema#', 'xsd:', $dt, $count );
 156+ if ( $count == 1 ) {
 157+ $this->post_ns_buffer .= '^^' . $newdt;
 158+ } else {
 159+ $this->post_ns_buffer .= '^^<' . $dt . '>';
 160+ }
 161+ }
 162+ }
 163+
 164+ protected function serializeExpResource( SMWExpResource $element ) {
 165+ if ( $element->isBlankNode() ) {
 166+ $this->post_ns_buffer .= '[]';
 167+ } else {
 168+ if ( $element->getQName() !== false ) {
 169+ $this->post_ns_buffer .= $element->getQName();
 170+ } else {
 171+ $this->post_ns_buffer .= '<' . str_replace( '>', '\>', SMWExporter::expandURI( $element->getName() ) ) . '>';
 172+ }
 173+ }
 174+ }
 175+
 176+}
Property changes on: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_Turtle.php
___________________________________________________________________
Added: svn:eol-style
1177 + native
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer.php
@@ -15,11 +15,16 @@
1616 define( 'SMW_SERIALIZER_DECL_APROP', 4 );
1717
1818 /**
19 - * Class for serializing exported data (encoded as SMWExpData object) in a
20 - * concrete syntactic format such as Turtle or RDF/XML. The serializer
 19+ * Abstract class for serializing exported data (encoded as SMWExpData object)
 20+ * in a concrete syntactic format such as Turtle or RDF/XML. The serializer
2121 * adds object serialisations to an internal string that can be retrieved for
22 - * pushing it to an output. RDF and OWL have two types of dependencies that are
23 - * managed: namespaces (and similar abbreviations) and element declarations.
 22+ * pushing it to an output. This abstract class does not define this string as
 23+ * implementations may want to use their own scheme (e.g. using two buffers as
 24+ * in the case of SMWRDFXMLSerializer). The function flushContent() returns the
 25+ * string serialized so far so as to enable incremental serialization.
 26+ *
 27+ * RDF and OWL have two types of dependencies that are managed by this class:
 28+ * namespaces (and similar abbreviation schemes) and element declarations.
2429 * The former need to be defined before being used, while the latter can occur
2530 * at some later point in the serialization. Declarations are relevant to the
2631 * OWL data model, being one of Class, DatatypeProperty, and ObjectProperty
@@ -28,8 +33,20 @@
2934 *
3035 * @ingroup SMW
3136 */
32 -class SMWSerializer {
 37+abstract class SMWSerializer {
3338 /**
 39+ * The current working string is obtained by concatenating the strings
 40+ * $pre_ns_buffer and $post_ns_buffer. The split between the two is such
 41+ * that one can append additional namespace declarations to $pre_ns_buffer
 42+ * so that they affect all current elements. The buffers are flushed during
 43+ * output in order to achieve "streaming" RDF export for larger files.
 44+ */
 45+ protected $pre_ns_buffer;
 46+ /**
 47+ * See documentation for $pre_ns_buffer.
 48+ */
 49+ protected $post_ns_buffer;
 50+ /**
3451 * Array for recording required declarations; format:
3552 * resourcename => decl-flag, where decl-flag is a sum of flags
3653 * SMW_SERIALIZER_DECL_CLASS, SMW_SERIALIZER_DECL_OPROP,
@@ -59,33 +76,6 @@
6077 * same abbreviation always refers to the same URI.
6178 */
6279 protected $global_namespaces;
63 - /**
64 - * The current working string is obtained by concatenating the strings
65 - * $pre_ns_buffer and $post_ns_buffer. The split between the two is such
66 - * that one can append additional namespace declarations to $pre_ns_buffer
67 - * so that they affect all current elements. The buffers are flushed during
68 - * output in order to achieve "streaming" RDF export for larger files.
69 - */
70 - protected $pre_ns_buffer;
71 - /**
72 - * See documentation for $pre_ns_buffer.
73 - */
74 - protected $post_ns_buffer;
75 - /**
76 - * True if the $pre_ns_buffer contains the beginning of a namespace
77 - * declaration block to which further declarations for the current
78 - * context can be appended.
79 - */
80 - protected $namespace_block_started;
81 - /**
82 - * True if the namespaces that are added at the current serialization stage
83 - * become global, i.e. remain available for all later contexts. This is the
84 - * case in RDF/XML only as long as the header has not been streamed to the
85 - * client (reflected herein by calling flushContent()). Later, namespaces
86 - * can only be added locally to individual elements, thus requiring them to
87 - * be re-added multiple times if used in many elements.
88 - */
89 - protected $namespaces_are_global;
9080
9181 /**
9282 * Constructor.
@@ -98,54 +88,45 @@
9989 * Clear internal states to start a new serialization.
10090 */
10191 public function clear() {
102 - $this->element_queue = array();
103 - $this->element_done = array();
104 - $this->decl_todo = array();
105 - $this->decl_done = array();
10692 $this->pre_ns_buffer = '';
10793 $this->post_ns_buffer = '';
108 - $this->namespaces_are_global = false;
 94+ $this->decl_todo = array();
 95+ $this->decl_done = array();
 96+ $this->global_namespaces = array();
10997 $this->extra_namespaces = array();
11098 }
11199
112 - /* Functions for exporting RDF */
113 -
114 - public function serializeHeader() {
 100+ /**
 101+ * Start a new serialization, resetting all internal data and serializing
 102+ * necessary header elements.
 103+ */
 104+ public function startSerialization() {
115105 $this->clear();
116 - $this->namespaces_are_global = true;
117 - $this->namespace_block_started = true;
118 - $this->pre_ns_buffer =
119 - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
120 - "<!DOCTYPE rdf:RDF[\n" .
121 - "\t<!ENTITY rdf " . $this->makeValueEntityString( SMWExporter::expandURI( '&rdf;' ) ) . ">\n" .
122 - "\t<!ENTITY rdfs " . $this->makeValueEntityString( SMWExporter::expandURI( '&rdfs;' ) ) . ">\n" .
123 - "\t<!ENTITY owl " . $this->makeValueEntityString( SMWExporter::expandURI( '&owl;' ) ) . ">\n" .
124 - "\t<!ENTITY swivt " . $this->makeValueEntityString( SMWExporter::expandURI( '&swivt;' ) ) . ">\n" .
125 - // A note on "wiki": this namespace is crucial as a fallback when it would be illegal to start e.g. with a number.
126 - // In this case, one can always use wiki:... followed by "_" and possibly some namespace, since _ is legal as a first character.
127 - "\t<!ENTITY wiki " . $this->makeValueEntityString( SMWExporter::expandURI( '&wiki;' ) ) . ">\n" .
128 - "\t<!ENTITY property " . $this->makeValueEntityString( SMWExporter::expandURI( '&property;' ) ) . ">\n" .
129 - "\t<!ENTITY wikiurl " . $this->makeValueEntityString( SMWExporter::expandURI( '&wikiurl;' ) ) . ">\n" .
130 - "]>\n\n" .
131 - "<rdf:RDF\n" .
132 - "\txmlns:rdf=\"&rdf;\"\n" .
133 - "\txmlns:rdfs=\"&rdfs;\"\n" .
134 - "\txmlns:owl =\"&owl;\"\n" .
135 - "\txmlns:swivt=\"&swivt;\"\n" .
136 - "\txmlns:wiki=\"&wiki;\"\n" .
137 - "\txmlns:property=\"&property;\"";
138 - $this->global_namespaces = array( 'rdf' => true, 'rdfs' => true, 'owl' => true, 'swivt' => true, 'wiki' => true, 'property' => true );
139 - $this->post_ns_buffer .= ">\n\n";
 106+ $this->serializeHeader();
140107 }
141108
142109 /**
143 - * Serialise the footer.
 110+ * Complete the serialization so that calling flushContent() will return
 111+ * the final part of the output, leading to a complete serialization with
 112+ * all necessary declarations. No further serialization functions must be
 113+ * called after this.
144114 */
145 - public function serializeFooter() {
 115+ public function finishSerialization() {
146116 $this->serializeDeclarations();
147 - $this->post_ns_buffer .= "\t<!-- Created by Semantic MediaWiki, http://semantic-mediawiki.org/ -->\n";
148 - $this->post_ns_buffer .= '</rdf:RDF>';
 117+ $this->serializeFooter();
149118 }
 119+
 120+ /**
 121+ * Serialize the header (i.e. write it to the internal buffer). May
 122+ * include standard syntax to start output but also declare some common
 123+ * namespaces globally.
 124+ */
 125+ abstract protected function serializeHeader();
 126+
 127+ /**
 128+ * Serialise the footer (i.e. write it to the internal buffer).
 129+ */
 130+ abstract protected function serializeFooter();
150131
151132 /**
152133 * Serialize any declarations that have been found to be missing while
@@ -157,8 +138,8 @@
158139 if ( $flag & SMW_SERIALIZER_DECL_CLASS ) $types[] = 'owl:Class';
159140 if ( $flag & SMW_SERIALIZER_DECL_OPROP ) $types[] = 'owl:ObjectProperty';
160141 if ( $flag & SMW_SERIALIZER_DECL_APROP ) $types[] = 'owl:DatatypeProperty';
161 - foreach ( $types as $type ) {
162 - $this->post_ns_buffer .= "\t<$type rdf:about=\"$name\" />\n";
 142+ foreach ( $types as $typename ) {
 143+ $this->serializeDeclaration( $name, $typename );
163144 }
164145 $curdone = array_key_exists( $name, $this->decl_done ) ? $this->decl_done[$name] : 0;
165146 $this->decl_done[$name] = $curdone | $flag;
@@ -167,107 +148,24 @@
168149 }
169150
170151 /**
171 - * Serialise the given SMWExpData object. The method does not assume that
172 - * the exported data refers to wiki pages or other SMW data, and it makes
173 - * sure that all required auxiliary declarations for obtaining proper OWL
174 - * are included anyway.
175 - *
176 - * @param $data SMWExpData containing the data to be serialised.
 152+ * Serialize a single declaration for the given $uri (expanded) and type
 153+ * (given as a QName).
 154+ * @param string $uri of the thing to declare
 155+ * @param string $typename one of owl:Class, owl:ObjectProperty, and
 156+ * owl:datatypeProperty
177157 */
178 - public function serializeExpData( SMWExpData $data ) {
179 - $this->serializeNestedExpData( $data, '' );
180 - $this->serializeNamespaces();
181 - if ( !$this->namespaces_are_global ) {
182 - $this->pre_ns_buffer .= $this->post_ns_buffer;
183 - $this->post_ns_buffer = '';
184 - $this->namespace_block_started = false;
185 - }
186 - }
187 -
 158+ abstract public function serializeDeclaration( $uri, $typename );
 159+
188160 /**
189 - * Serialise the given SMWExpData object, possibly recursively with
190 - * increased indentation.
 161+ * Serialise the given SMWExpData object. The method must not assume that
 162+ * the exported data refers to wiki pages or other SMW data, and it must
 163+ * ensure that all required auxiliary declarations for obtaining proper OWL
 164+ * are included in any case (this can be done using requireDeclaration()).
191165 *
192166 * @param $data SMWExpData containing the data to be serialised.
193 - * @param $indent string specifying a prefix for indentation (usually a sequence of tabs)
194167 */
195 - protected function serializeNestedExpData( SMWExpData $data, $indent ) {
196 - $this->recordDeclarationTypes( $data );
 168+ abstract public function serializeExpData( SMWExpData $data );
197169
198 - $type = $data->extractMainType()->getQName();
199 - if ( !$this->namespace_block_started ) { // start new ns block
200 - $this->pre_ns_buffer .= "\t$indent<$type";
201 - $this->namespace_block_started = true;
202 - } else { // continue running block
203 - $this->post_ns_buffer .= "\t$indent<$type";
204 - }
205 -
206 - if ( ( $data->getSubject() instanceof SMWExpLiteral ) ||
207 - ( $data->getSubject() instanceof SMWExpResource ) ) {
208 - $this->post_ns_buffer .= ' rdf:about="' . $data->getSubject()->getName() . '"';
209 - } // else: blank node, no "rdf:about"
210 -
211 - if ( count( $data->getProperties() ) == 0 ) { // nothing else to export
212 - $this->post_ns_buffer .= " />\n";
213 - } else { // process data
214 - $this->post_ns_buffer .= ">\n";
215 -
216 - foreach ( $data->getProperties() as $property ) {
217 - $prop_decl_queued = false;
218 - $prop_decl_type = 0;
219 - $class_type_prop = $this->isOWLClassTypeProperty( $property );
220 -
221 - foreach ( $data->getValues( $property ) as $value ) {
222 - $this->post_ns_buffer .= "\t\t$indent<" . $property->getQName();
223 - $this->requireNamespace( $property->getNamespaceID(), $property->getNamespace() );
224 - $object = $value->getSubject();
225 -
226 - if ( $object instanceof SMWExpLiteral ) {
227 - $prop_decl_type = SMW_SERIALIZER_DECL_APROP;
228 - if ( $object->getDatatype() != '' ) {
229 - $this->post_ns_buffer .= ' rdf:datatype="' . $object->getDatatype() . '"';
230 - }
231 - $this->post_ns_buffer .= '>' .
232 - str_replace( array( '&', '>', '<' ), array( '&amp;', '&gt;', '&lt;' ), $object->getName() ) .
233 - '</' . $property->getQName() . ">\n";
234 - } else { // resource (maybe blank node), could have subdescriptions
235 - $prop_decl_type = SMW_SERIALIZER_DECL_OPROP;
236 - $collection = $value->getCollection();
237 - if ( $collection !== false ) { // RDF-style collection (list)
238 - $this->post_ns_buffer .= " rdf:parseType=\"Collection\">\n";
239 - foreach ( $collection as $subvalue ) {
240 - $this->serializeNestedExpData( $subvalue, $indent . "\t\t" );
241 - if ( $class_type_prop ) {
242 - $this->requireDeclaration( $subvalue, SMW_SERIALIZER_DECL_CLASS );
243 - }
244 - }
245 - $this->post_ns_buffer .= "\t\t$indent</" . $property->getQName() . ">\n";
246 - } else {
247 - if ( $class_type_prop ) {
248 - $this->requireDeclaration( $object, SMW_SERIALIZER_DECL_CLASS );
249 - }
250 - if ( count( $value->getProperties() ) > 0 ) { // resource with data: serialise
251 - $this->post_ns_buffer .= ">\n";
252 - $this->serializeNestedExpData( $value, $indent . "\t\t" );
253 - $this->post_ns_buffer .= "\t\t$indent</" . $property->getQName() . ">\n";
254 - } else { // resource without data: may need to be queued
255 - if ( !$object->isBlankNode() ) {
256 - $this->post_ns_buffer .= ' rdf:resource="' . $object->getName() . '"';
257 - }
258 - $this->post_ns_buffer .= "/>\n";
259 - }
260 - }
261 - }
262 - if ( !$prop_decl_queued ) {
263 - $this->requireDeclaration( $property, $prop_decl_type );
264 - $prop_decl_queued = true;
265 - }
266 - }
267 - }
268 - $this->post_ns_buffer .= "\t$indent</" . $type . ">\n";
269 - }
270 - }
271 -
272170 /**
273171 * Get the string that has been serialized so far. This function also
274172 * resets the internal buffers for serilized strings and namespaces
@@ -276,15 +174,33 @@
277175 public function flushContent() {
278176 if ( ( $this->pre_ns_buffer == '' ) && ( $this->post_ns_buffer == '' ) ) return '';
279177 $this->serializeNamespaces();
280 - $this->namespaces_are_global = false;
281178 $result = $this->pre_ns_buffer . $this->post_ns_buffer;
282179 $this->pre_ns_buffer = '';
283180 $this->post_ns_buffer = '';
284 - $this->namespace_block_started = false;
285181 return $result;
286182 }
287183
288184 /**
 185+ * Include collected namespace information into the serialization.
 186+ */
 187+ protected function serializeNamespaces() {
 188+ foreach ( $this->extra_namespaces as $nsshort => $nsuri ) {
 189+ $this->serializeNamespace( $nsshort, $nsuri );
 190+ }
 191+ $this->extra_namespaces = array();
 192+ }
 193+
 194+ /**
 195+ * Serialize a single namespace.
 196+ * Namespaces that were serialized in such a way that they remain
 197+ * available for all following output should be added to
 198+ * $global_namespaces.
 199+ * @param string $shortname the abbreviation/prefix to declare
 200+ * @param string $uri the URI prefix that the namespace encodes
 201+ */
 202+ abstract protected function serializeNamespace( $shortname, $uri );
 203+
 204+ /**
289205 * Require an additional namespace to be declared in the serialization.
290206 * The function checks whether the required namespace is available globally
291207 * and add it to the list of required namespaces otherwise.
@@ -294,22 +210,6 @@
295211 $this->extra_namespaces[$nsshort] = $nsuri;
296212 }
297213 }
298 -
299 - /**
300 - * Include collected namespace information into the serialization.
301 - */
302 - protected function serializeNamespaces() {
303 - foreach ( $this->extra_namespaces as $nsshort => $nsuri ) {
304 - if ( $this->namespaces_are_global ) {
305 - $this->global_namespaces[$nsshort] = true;
306 - $this->pre_ns_buffer .= "\n\t";
307 - } else {
308 - $this->pre_ns_buffer .= ' ';
309 - }
310 - $this->pre_ns_buffer .= "xmlns:$nsshort=\"$nsuri\"";
311 - }
312 - $this->extra_namespaces = array();
313 - }
314214
315215 /**
316216 * State that a certain declaration is needed. The method checks if the
@@ -405,15 +305,5 @@
406306 return false;
407307 }
408308 }
409 -
410 - /**
411 - * Escape a string in the special form that is required for values in
412 - * DTD entity declarations in XML. Namely, this require the percent sign
413 - * to be replaced.
414 - * @param string $string to be escaped
415 - */
416 - protected function makeValueEntityString( $string ) {
417 - return "'" . str_replace( '%','&#37;',$string ) . "'";
418 - }
419309
420310 }
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_Setup.php
@@ -127,6 +127,7 @@
128128 $wgAutoloadClasses['SMWRSSResultPrinter'] = $qpDir . 'SMW_QP_RSSlink.php';
129129 $wgAutoloadClasses['SMWCsvResultPrinter'] = $qpDir . 'SMW_QP_CSV.php';
130130 $wgAutoloadClasses['SMWJSONResultPrinter'] = $qpDir . 'SMW_QP_JSONlink.php';
 131+ $wgAutoloadClasses['SMWRDFResultPrinter'] = $qpDir . 'SMW_QP_RDF.php';
131132
132133 // Datavalues
133134 $dvDir = $smwgIP . 'includes/datavalues/';
@@ -158,6 +159,8 @@
159160 $wgAutoloadClasses['SMWExpResource'] = $expDir . 'SMW_Exp_Element.php';
160161 $wgAutoloadClasses['SMWExportController'] = $expDir . 'SMW_ExportController.php';
161162 $wgAutoloadClasses['SMWSerializer'] = $expDir . 'SMW_Serializer.php';
 163+ $wgAutoloadClasses['SMWRDFXMLSerializer'] = $expDir . 'SMW_Serializer_RDFXML.php';
 164+ $wgAutoloadClasses['SMWTurtleSerializer'] = $expDir . 'SMW_Serializer_Turtle.php';
162165
163166 // Parser hooks
164167 $phDir = $smwgIP . 'includes/parserhooks/';

Status & tagging log