Index: trunk/extensions/SemanticMediaWiki/specials/Export/SMW_SpecialOWLExport.php |
— | — | @@ -104,16 +104,24 @@ |
105 | 105 | */ |
106 | 106 | protected function startRDFExport() { |
107 | 107 | global $wgOut, $wgRequest; |
| 108 | + $format = $wgRequest->getText( 'format' ); |
| 109 | + if ( $format == '' ) $format = $wgRequest->getVal( 'format' ); |
108 | 110 | $wgOut->disable(); |
109 | 111 | 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(); |
116 | 123 | } |
117 | | - $this->export_controller = new SMWExportController( new SMWSerializer() ); |
| 124 | + header( "Content-type: $mimetype; charset=UTF-8" ); |
| 125 | + $this->export_controller = new SMWExportController( $serializer ); |
118 | 126 | } |
119 | 127 | |
120 | 128 | /** |
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_ExportController.php |
— | — | @@ -354,24 +354,6 @@ |
355 | 355 | flush(); |
356 | 356 | } |
357 | 357 | } |
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 | | - } |
376 | 358 | |
377 | 359 | /** |
378 | 360 | * This function prints all selected pages, specified as an array of page |
— | — | @@ -411,21 +393,21 @@ |
412 | 394 | $this->element_queue[$st->getHash()] = $st; |
413 | 395 | } |
414 | 396 | |
415 | | - $this->serializer->serializeHeader(); |
| 397 | + $this->serializer->startSerialization(); |
416 | 398 | |
417 | 399 | if ( count( $pages ) == 1 ) { // ensure that ontologies that are retrieved as linked data are not confused with their subject! |
418 | 400 | $ontologyuri = SMWExporter::expandURI( '&export;' ) . '/' . urlencode( end( $pages ) ); |
419 | 401 | } else { // use empty URI, i.e. "location" as URI otherwise |
420 | 402 | $ontologyuri = ''; |
421 | 403 | } |
422 | | - $this->serializer->serializeExpData( $this->getOntologyExpData( $ontologyuri ) ); |
| 404 | + $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( $ontologyuri ) ); |
423 | 405 | |
424 | 406 | while ( count( $this->element_queue ) > 0 ) { |
425 | 407 | $this->serializeSmallTitle( reset( $this->element_queue ) ); |
426 | 408 | $this->flush(); |
427 | 409 | $linkCache->clear(); // avoid potential memory leak |
428 | 410 | } |
429 | | - $this->serializer->serializeFooter(); |
| 411 | + $this->serializer->finishSerialization(); |
430 | 412 | $this->flush( true ); |
431 | 413 | |
432 | 414 | wfProfileOut( "RDF::PrintPages" ); |
— | — | @@ -450,8 +432,8 @@ |
451 | 433 | $this->delay_flush = 10; |
452 | 434 | if ( !$this->prepareSerialization( $outfile ) ) return; |
453 | 435 | |
454 | | - $this->serializer->serializeHeader(); |
455 | | - $this->serializer->serializeExpData( $this->getOntologyExpData( '' ) ); |
| 436 | + $this->serializer->startSerialization(); |
| 437 | + $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( '' ) ); |
456 | 438 | |
457 | 439 | $end = $db->selectField( 'page', 'max(page_id)', false, $outfile ); |
458 | 440 | $a_count = 0; $d_count = 0; // DEBUG |
— | — | @@ -493,7 +475,7 @@ |
494 | 476 | $linkCache->clear(); |
495 | 477 | } |
496 | 478 | |
497 | | - $this->serializer->serializeFooter(); |
| 479 | + $this->serializer->finishSerialization(); |
498 | 480 | $this->flush( true ); |
499 | 481 | } |
500 | 482 | |
— | — | @@ -514,8 +496,8 @@ |
515 | 497 | $this->delay_flush = 35; // don't do intermediate flushes with default parameters |
516 | 498 | $linkCache = LinkCache::singleton(); |
517 | 499 | |
518 | | - $this->serializer->serializeHeader(); |
519 | | - $this->serializer->serializeExpData( $this->getOntologyExpData( '' ) ); |
| 500 | + $this->serializer->startSerialization(); |
| 501 | + $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( '' ) ); |
520 | 502 | |
521 | 503 | $query = ''; |
522 | 504 | foreach ( $smwgNamespacesWithSemanticLinks as $ns => $enabled ) { |
— | — | @@ -554,7 +536,7 @@ |
555 | 537 | $this->serializer->serializeExpData( $data ); |
556 | 538 | } |
557 | 539 | |
558 | | - $this->serializer->serializeFooter(); |
| 540 | + $this->serializer->finishSerialization(); |
559 | 541 | $this->flush( true ); |
560 | 542 | |
561 | 543 | wfProfileOut( "RDF::PrintPageList" ); |
— | — | @@ -610,8 +592,8 @@ |
611 | 593 | $ed = new SMWExpData( new SMWExpLiteral( SiteStats::admins(), null, 'http://www.w3.org/2001/XMLSchema#int' ) ); |
612 | 594 | $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'swivt', 'adminCount' ), $ed ); |
613 | 595 | |
614 | | - $this->serializer->serializeHeader(); |
615 | | - $this->serializer->serializeExpData( $this->getOntologyExpData( '' ) ); |
| 596 | + $this->serializer->startSerialization(); |
| 597 | + $this->serializer->serializeExpData( SMWExporter::getOntologyExpData( '' ) ); |
616 | 598 | $this->serializer->serializeExpData( $data ); |
617 | 599 | |
618 | 600 | // link to list of existing pages: |
— | — | @@ -627,7 +609,7 @@ |
628 | 610 | $data->addPropertyObjectValue( SMWExporter::getSpecialElement( 'rdfs', 'isDefinedBy' ), $ed ); |
629 | 611 | $this->serializer->serializeExpData( $data ); |
630 | 612 | |
631 | | - $this->serializer->serializeFooter(); |
| 613 | + $this->serializer->finishSerialization(); |
632 | 614 | $this->flush( true ); |
633 | 615 | |
634 | 616 | 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( '&', '>', '<' ), $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( '%','%',$string ) . "'"; |
| 198 | + } |
| 199 | + |
| 200 | +} |
Property changes on: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer_RDFXML.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 201 | + native |
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Exporter.php |
— | — | @@ -56,36 +56,52 @@ |
57 | 57 | static public function makeExportData( /*SMWSemanticData*/ $semdata, $modifier = '' ) { |
58 | 58 | SMWExporter::initBaseURIs(); |
59 | 59 | $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 ) { |
60 | 86 | $result = $subject->getExportData(); |
61 | | - |
62 | | - // first set some general parameters for export |
63 | | - $category_pe = null; |
64 | | - $subprop_pe = null; |
65 | 87 | switch ( $subject->getNamespace() ) { |
66 | 88 | case NS_CATEGORY: case SMW_NS_CONCEPT: |
67 | | - $category_pe = SMWExporter::getSpecialElement( 'rdfs', 'subClassOf' ); |
68 | | - $equality_pe = SMWExporter::getSpecialElement( 'owl', 'equivalentClass' ); |
69 | 89 | $maintype_pe = SMWExporter::getSpecialElement( 'owl', 'Class' ); |
70 | 90 | $label = $subject->getText(); |
71 | 91 | break; |
72 | 92 | 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 ) ); |
78 | 98 | $label = $subject->getText(); |
79 | 99 | break; |
80 | 100 | default: |
81 | | - $category_pe = SMWExporter::getSpecialElement( 'rdf', 'type' ); |
82 | | - $equality_pe = SMWExporter::getSpecialElement( 'owl', 'sameAs' ); |
| 101 | + $label = $subject->getWikiValue(); |
83 | 102 | $maintype_pe = SMWExporter::getSpecialElement( 'swivt', 'Subject' ); |
84 | | - $label = $subject->getWikiValue(); |
85 | 103 | } |
86 | | - |
87 | | - // export standard properties |
88 | 104 | if ( $modifier != '' ) { |
89 | | - $modifier = smwfHTMLtoUTF8( $modifier ); ///TODO: check if this is needed anymore |
| 105 | + $modifier = smwfHTMLtoUTF8( $modifier ); ///TODO: check if this is still needed |
90 | 106 | $label .= ' (' . $modifier . ')'; |
91 | 107 | } |
92 | 108 | $ed = new SMWExpData( new SMWExpLiteral( $label ) ); |
— | — | @@ -106,75 +122,94 @@ |
107 | 123 | } |
108 | 124 | $result->setSubject( $result->getSubject()->makeVariant( $modifier ) ); |
109 | 125 | } |
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; |
120 | 147 | } |
| 148 | + $data->addPropertyObjectValue( $pem, $ed ); |
121 | 149 | } |
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 { |
130 | 185 | $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 | + } |
149 | 196 | } |
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 ); |
168 | 205 | } |
169 | | - } else { |
170 | | - $result->addPropertyObjectValue( $pe, $ed ); |
171 | 206 | } |
172 | 207 | } |
| 208 | + } else { |
| 209 | + $data->addPropertyObjectValue( $pe, $ed ); |
173 | 210 | } |
174 | 211 | } |
175 | 212 | } |
176 | 213 | } |
177 | | - |
178 | | - return $result; |
179 | 214 | } |
180 | 215 | |
181 | 216 | /** |
— | — | @@ -298,4 +333,22 @@ |
299 | 334 | return $uri; |
300 | 335 | } |
301 | 336 | |
| 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 | + |
302 | 355 | } |
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 |
1 | 177 | + native |
Index: trunk/extensions/SemanticMediaWiki/includes/export/SMW_Serializer.php |
— | — | @@ -15,11 +15,16 @@ |
16 | 16 | define( 'SMW_SERIALIZER_DECL_APROP', 4 ); |
17 | 17 | |
18 | 18 | /** |
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 |
21 | 21 | * 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. |
24 | 29 | * The former need to be defined before being used, while the latter can occur |
25 | 30 | * at some later point in the serialization. Declarations are relevant to the |
26 | 31 | * OWL data model, being one of Class, DatatypeProperty, and ObjectProperty |
— | — | @@ -28,8 +33,20 @@ |
29 | 34 | * |
30 | 35 | * @ingroup SMW |
31 | 36 | */ |
32 | | -class SMWSerializer { |
| 37 | +abstract class SMWSerializer { |
33 | 38 | /** |
| 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 | + /** |
34 | 51 | * Array for recording required declarations; format: |
35 | 52 | * resourcename => decl-flag, where decl-flag is a sum of flags |
36 | 53 | * SMW_SERIALIZER_DECL_CLASS, SMW_SERIALIZER_DECL_OPROP, |
— | — | @@ -59,33 +76,6 @@ |
60 | 77 | * same abbreviation always refers to the same URI. |
61 | 78 | */ |
62 | 79 | 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; |
90 | 80 | |
91 | 81 | /** |
92 | 82 | * Constructor. |
— | — | @@ -98,54 +88,45 @@ |
99 | 89 | * Clear internal states to start a new serialization. |
100 | 90 | */ |
101 | 91 | public function clear() { |
102 | | - $this->element_queue = array(); |
103 | | - $this->element_done = array(); |
104 | | - $this->decl_todo = array(); |
105 | | - $this->decl_done = array(); |
106 | 92 | $this->pre_ns_buffer = ''; |
107 | 93 | $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(); |
109 | 97 | $this->extra_namespaces = array(); |
110 | 98 | } |
111 | 99 | |
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() { |
115 | 105 | $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(); |
140 | 107 | } |
141 | 108 | |
142 | 109 | /** |
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. |
144 | 114 | */ |
145 | | - public function serializeFooter() { |
| 115 | + public function finishSerialization() { |
146 | 116 | $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(); |
149 | 118 | } |
| 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(); |
150 | 131 | |
151 | 132 | /** |
152 | 133 | * Serialize any declarations that have been found to be missing while |
— | — | @@ -157,8 +138,8 @@ |
158 | 139 | if ( $flag & SMW_SERIALIZER_DECL_CLASS ) $types[] = 'owl:Class'; |
159 | 140 | if ( $flag & SMW_SERIALIZER_DECL_OPROP ) $types[] = 'owl:ObjectProperty'; |
160 | 141 | 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 ); |
163 | 144 | } |
164 | 145 | $curdone = array_key_exists( $name, $this->decl_done ) ? $this->decl_done[$name] : 0; |
165 | 146 | $this->decl_done[$name] = $curdone | $flag; |
— | — | @@ -167,107 +148,24 @@ |
168 | 149 | } |
169 | 150 | |
170 | 151 | /** |
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 |
177 | 157 | */ |
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 | + |
188 | 160 | /** |
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()). |
191 | 165 | * |
192 | 166 | * @param $data SMWExpData containing the data to be serialised. |
193 | | - * @param $indent string specifying a prefix for indentation (usually a sequence of tabs) |
194 | 167 | */ |
195 | | - protected function serializeNestedExpData( SMWExpData $data, $indent ) { |
196 | | - $this->recordDeclarationTypes( $data ); |
| 168 | + abstract public function serializeExpData( SMWExpData $data ); |
197 | 169 | |
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( '&', '>', '<' ), $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 | | - |
272 | 170 | /** |
273 | 171 | * Get the string that has been serialized so far. This function also |
274 | 172 | * resets the internal buffers for serilized strings and namespaces |
— | — | @@ -276,15 +174,33 @@ |
277 | 175 | public function flushContent() { |
278 | 176 | if ( ( $this->pre_ns_buffer == '' ) && ( $this->post_ns_buffer == '' ) ) return ''; |
279 | 177 | $this->serializeNamespaces(); |
280 | | - $this->namespaces_are_global = false; |
281 | 178 | $result = $this->pre_ns_buffer . $this->post_ns_buffer; |
282 | 179 | $this->pre_ns_buffer = ''; |
283 | 180 | $this->post_ns_buffer = ''; |
284 | | - $this->namespace_block_started = false; |
285 | 181 | return $result; |
286 | 182 | } |
287 | 183 | |
288 | 184 | /** |
| 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 | + /** |
289 | 205 | * Require an additional namespace to be declared in the serialization. |
290 | 206 | * The function checks whether the required namespace is available globally |
291 | 207 | * and add it to the list of required namespaces otherwise. |
— | — | @@ -294,22 +210,6 @@ |
295 | 211 | $this->extra_namespaces[$nsshort] = $nsuri; |
296 | 212 | } |
297 | 213 | } |
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 | | - } |
314 | 214 | |
315 | 215 | /** |
316 | 216 | * State that a certain declaration is needed. The method checks if the |
— | — | @@ -405,15 +305,5 @@ |
406 | 306 | return false; |
407 | 307 | } |
408 | 308 | } |
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( '%','%',$string ) . "'"; |
418 | | - } |
419 | 309 | |
420 | 310 | } |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_Setup.php |
— | — | @@ -127,6 +127,7 @@ |
128 | 128 | $wgAutoloadClasses['SMWRSSResultPrinter'] = $qpDir . 'SMW_QP_RSSlink.php'; |
129 | 129 | $wgAutoloadClasses['SMWCsvResultPrinter'] = $qpDir . 'SMW_QP_CSV.php'; |
130 | 130 | $wgAutoloadClasses['SMWJSONResultPrinter'] = $qpDir . 'SMW_QP_JSONlink.php'; |
| 131 | + $wgAutoloadClasses['SMWRDFResultPrinter'] = $qpDir . 'SMW_QP_RDF.php'; |
131 | 132 | |
132 | 133 | // Datavalues |
133 | 134 | $dvDir = $smwgIP . 'includes/datavalues/'; |
— | — | @@ -158,6 +159,8 @@ |
159 | 160 | $wgAutoloadClasses['SMWExpResource'] = $expDir . 'SMW_Exp_Element.php'; |
160 | 161 | $wgAutoloadClasses['SMWExportController'] = $expDir . 'SMW_ExportController.php'; |
161 | 162 | $wgAutoloadClasses['SMWSerializer'] = $expDir . 'SMW_Serializer.php'; |
| 163 | + $wgAutoloadClasses['SMWRDFXMLSerializer'] = $expDir . 'SMW_Serializer_RDFXML.php'; |
| 164 | + $wgAutoloadClasses['SMWTurtleSerializer'] = $expDir . 'SMW_Serializer_Turtle.php'; |
162 | 165 | |
163 | 166 | // Parser hooks |
164 | 167 | $phDir = $smwgIP . 'includes/parserhooks/'; |