namespaces_are_global = false; $this->namespace_block_started = false; } protected function serializeHeader() { $this->namespaces_are_global = true; $this->namespace_block_started = true; $this->pre_ns_buffer = "\n" . "makeValueEntityString( SMWExporter::getInstance()->expandURI( '&rdf;' ) ) . ">\n" . "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&rdfs;' ) ) . ">\n" . "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&owl;' ) ) . ">\n" . "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&swivt;' ) ) . ">\n" . // A note on "wiki": this namespace is crucial as a fallback when it would be illegal to start e.g. with a number. // In this case, one can always use wiki:... followed by "_" and possibly some namespace, since _ is legal as a first character. "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&wiki;' ) ) . ">\n" . "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&category;' ) ) . ">\n" . "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&property;' ) ) . ">\n" . "\tmakeValueEntityString( SMWExporter::getInstance()->expandURI( '&wikiurl;' ) ) . ">\n" . "]>\n\n" . "global_namespaces = [ 'rdf' => true, 'rdfs' => true, 'owl' => true, 'swivt' => true, 'wiki' => true, 'property' => true, 'category' => true ]; $this->post_ns_buffer .= ">\n\n"; } protected function serializeFooter() { $this->post_ns_buffer .= "\t\n"; $this->post_ns_buffer .= ''; } public function serializeDeclaration( $uri, $typename ) { $this->post_ns_buffer .= "\t<$typename rdf:about=\"$uri\" />\n"; } public function serializeExpData( SMWExpData $expData ) { $this->serializeNestedExpData( $expData, '' ); $this->serializeNamespaces(); if ( !$this->namespaces_are_global ) { $this->pre_ns_buffer .= $this->post_ns_buffer; $this->post_ns_buffer = ''; $this->namespace_block_started = false; } } public function flushContent() { $result = parent::flushContent(); $this->namespaces_are_global = false; // must not be done before calling the parent method (which may declare namespaces) $this->namespace_block_started = false; return $result; } protected function serializeNamespace( $shortname, $uri ) { if ( $this->namespaces_are_global ) { $this->global_namespaces[$shortname] = true; $this->pre_ns_buffer .= "\n\t"; } else { $this->pre_ns_buffer .= ' '; } $this->pre_ns_buffer .= "xmlns:$shortname=\"$uri\""; } /** * Serialize the given SMWExpData object, possibly recursively with * increased indentation. * * @param $expData SMWExpData containing the data to be serialised. * @param $indent string specifying a prefix for indentation (usually a sequence of tabs) */ protected function serializeNestedExpData( SMWExpData $expData, $indent ) { $this->recordDeclarationTypes( $expData ); $type = $expData->extractMainType()->getQName(); if ( !$this->namespace_block_started ) { // start new ns block $this->pre_ns_buffer .= "\t$indent<$type"; $this->namespace_block_started = true; } else { // continue running block $this->post_ns_buffer .= "\t$indent<$type"; } if ( ( $expData->getSubject() instanceof SMWExpResource ) && !$expData->getSubject()->isBlankNode() ) { $this->post_ns_buffer .= ' rdf:about="' . $expData->getSubject()->getUri() . '"'; } // else: blank node, no "rdf:about" if ( count( $expData->getProperties() ) == 0 ) { // nothing else to export $this->post_ns_buffer .= " />\n"; } else { // process data $this->post_ns_buffer .= ">\n"; foreach ( $expData->getProperties() as $property ) { $prop_decl_queued = false; $isClassTypeProp = $this->isOWLClassTypeProperty( $property ); foreach ( $expData->getValues( $property ) as $valueElement ) { $this->requireNamespace( $property->getNamespaceID(), $property->getNamespace() ); if ( $valueElement instanceof SMWExpLiteral ) { $prop_decl_type = SMW_SERIALIZER_DECL_APROP; $this->serializeExpLiteral( $property, $valueElement, "\t\t$indent" ); } elseif ( $valueElement instanceof SMWExpResource ) { $prop_decl_type = SMW_SERIALIZER_DECL_OPROP; $this->serializeExpResource( $property, $valueElement, "\t\t$indent", $isClassTypeProp ); } elseif ( $valueElement instanceof SMWExpData ) { $prop_decl_type = SMW_SERIALIZER_DECL_OPROP; $collection = $valueElement->getCollection(); if ( $collection !== false ) { // RDF-style collection (list) $this->serializeExpCollection( $property, $collection, "\t\t$indent", $isClassTypeProp ); } elseif ( count( $valueElement->getProperties() ) > 0 ) { // resource with data $this->post_ns_buffer .= "\t\t$indent<" . $property->getQName() . ">\n"; $this->serializeNestedExpData( $valueElement, "\t\t$indent" ); $this->post_ns_buffer .= "\t\t$indentgetQName() . ">\n"; } else { // resource without data $this->serializeExpResource( $property, $valueElement->getSubject(), "\t\t$indent", $isClassTypeProp ); } } // else: no other types of export elements if ( !$prop_decl_queued ) { $this->requireDeclaration( $property, $prop_decl_type ); $prop_decl_queued = true; } } } $this->post_ns_buffer .= "\t$indent\n"; } } /** * Add to the output a serialization of a property assignment where an * SMWExpLiteral is the object. It is assumed that a suitable subject * block has already been openend. * * @param $expResourceProperty SMWExpNsResource the property to use * @param $expLiteral SMWExpLiteral the data value to use * @param $indent string specifying a prefix for indentation (usually a sequence of tabs) */ protected function serializeExpLiteral( SMWExpNsResource $expResourceProperty, SMWExpLiteral $expLiteral, $indent ) { $this->post_ns_buffer .= $indent . '<' . $expResourceProperty->getQName(); // https://www.w3.org/TR/rdf-syntax-grammar/#section-Syntax-languages // "... to indicate that the included content is in the given language. // Typed literals which includes XML literals are not affected by this // attribute. The most specific in-scope language present (if any) is // applied to property element string literal ..." if ( $expLiteral->getDatatype() !== '' && $expLiteral->getLang() !== '' ) { $this->post_ns_buffer .= ' xml:lang="' . $expLiteral->getLang() . '"'; } elseif ( $expLiteral->getDatatype() !== '' ) { $this->post_ns_buffer .= ' rdf:datatype="' . $expLiteral->getDatatype() . '"'; } $this->post_ns_buffer .= '>' . $this->makeAttributeValueString( $expLiteral->getLexicalForm() ); $this->post_ns_buffer .= 'getQName() . ">\n"; } /** * Add to the output a serialization of a property assignment where an * SMWExpResource is the object. It is assumed that a suitable subject * block has already been openend. * * @param $expResourceProperty SMWExpNsResource the property to use * @param $expResource SMWExpResource the data value to use * @param $indent string specifying a prefix for indentation (usually a sequence of tabs) * @param $isClassTypeProp boolean whether the resource must be declared as a class */ protected function serializeExpResource( SMWExpNsResource $expResourceProperty, SMWExpResource $expResource, $indent, $isClassTypeProp ) { $this->post_ns_buffer .= $indent . '<' . $expResourceProperty->getQName(); if ( !$expResource->isBlankNode() ) { if ( ( $expResource instanceof SMWExpNsResource ) && ( $expResource->getNamespaceID() == 'wiki' ) ) { // very common case, reduce bandwidth $this->post_ns_buffer .= ' rdf:resource="&wiki;' . $expResource->getLocalName() . '"'; } else { $uriValue = $this->makeAttributeValueString( $expResource->getUri() ); $this->post_ns_buffer .= ' rdf:resource="' . $uriValue . '"'; } } $this->post_ns_buffer .= "/>\n"; if ( $isClassTypeProp ) { $this->requireDeclaration( $expResource, SMW_SERIALIZER_DECL_CLASS ); } } /** * Add a serialization of the given SMWExpResource to the output, * assuming that an opening property tag is alerady there. * * @param $expResourceProperty SMWExpNsResource the property to use * @param $expResource array of (SMWExpResource or SMWExpData) * @param $indent string specifying a prefix for indentation (usually a sequence of tabs) * @param $isClassTypeProp boolean whether the resource must be declared as a class * * @bug The $isClassTypeProp parameter is not properly taken into account. * @bug Individual resources are not serialised properly. */ protected function serializeExpCollection( SMWExpNsResource $expResourceProperty, array $collection, $indent, $isClassTypeProp ) { $this->post_ns_buffer .= $indent . '<' . $expResourceProperty->getQName() . " rdf:parseType=\"Collection\">\n"; foreach ( $collection as $expElement ) { if ( $expElement instanceof SMWExpData ) { $this->serializeNestedExpData( $expElement, $indent ); } else { // FIXME: the below is not the right thing to do here //$this->serializeExpResource( $expResourceProperty, $expElement, $indent ); } if ( $isClassTypeProp ) { // FIXME: $expResource is undefined //$this->requireDeclaration( $expResource, SMW_SERIALIZER_DECL_CLASS ); } } $this->post_ns_buffer .= "$indentgetQName() . ">\n"; } /** * Escape a string in the special form that is required for values in * DTD entity declarations in XML. Namely, this require the percent sign * to be replaced. * * @param $string string to be escaped * @return string */ protected function makeValueEntityString( $string ) { return "'" . str_replace( '%', '%', $string ) . "'"; } /** * Escape a string as required for using it in XML attribute values. * * @param $string string to be escaped * @return string */ protected function makeAttributeValueString( $string ) { return str_replace( [ '&', '>', '<' ], [ '&', '>', '<' ], $string ); } }