MediaWiki  REL1_21
ApiFormatXml.php
Go to the documentation of this file.
00001 <?php
00031 class ApiFormatXml extends ApiFormatBase {
00032 
00033         private $mRootElemName = 'api';
00034         public static $namespace = 'http://www.mediawiki.org/xml/api/';
00035         private $mDoubleQuote = false;
00036         private $mIncludeNamespace = false;
00037         private $mXslt = null;
00038 
00039         public function getMimeType() {
00040                 return 'text/xml';
00041         }
00042 
00043         public function getNeedsRawData() {
00044                 return true;
00045         }
00046 
00047         public function setRootElement( $rootElemName ) {
00048                 $this->mRootElemName = $rootElemName;
00049         }
00050 
00051         public function execute() {
00052                 $params = $this->extractRequestParams();
00053                 $this->mDoubleQuote = $params['xmldoublequote'];
00054                 $this->mIncludeNamespace = $params['includexmlnamespace'];
00055                 $this->mXslt = $params['xslt'];
00056 
00057                 $this->printText( '<?xml version="1.0"?>' );
00058                 if ( !is_null( $this->mXslt ) ) {
00059                         $this->addXslt();
00060                 }
00061                 if ( $this->mIncludeNamespace ) {
00062                         // If the result data already contains an 'xmlns' namespace added
00063                         // for custom XML output types, it will override the one for the
00064                         // generic API results.
00065                         // This allows API output of other XML types like Atom, RSS, RSD.
00066                         $data = $this->getResultData() + array( 'xmlns' => self::$namespace );
00067                 } else {
00068                         $data = $this->getResultData();
00069                 }
00070 
00071                 $this->printText(
00072                         self::recXmlPrint( $this->mRootElemName,
00073                                 $data,
00074                                 $this->getIsHtml() ? - 2 : null,
00075                                 $this->mDoubleQuote
00076                         )
00077                 );
00078         }
00079 
00124         public static function recXmlPrint( $elemName, $elemValue, $indent, $doublequote = false ) {
00125                 $retval = '';
00126                 if ( !is_null( $indent ) ) {
00127                         $indent += 2;
00128                         $indstr = "\n" . str_repeat( ' ', $indent );
00129                 } else {
00130                         $indstr = '';
00131                 }
00132                 $elemName = str_replace( ' ', '_', $elemName );
00133 
00134                 switch ( gettype( $elemValue ) ) {
00135                         case 'array':
00136                                 if ( isset( $elemValue['*'] ) ) {
00137                                         $subElemContent = $elemValue['*'];
00138                                         if ( $doublequote ) {
00139                                                 $subElemContent = Sanitizer::encodeAttribute( $subElemContent );
00140                                         }
00141                                         unset( $elemValue['*'] );
00142 
00143                                         // Add xml:space="preserve" to the
00144                                         // element so XML parsers will leave
00145                                         // whitespace in the content alone
00146                                         $elemValue['xml:space'] = 'preserve';
00147                                 } else {
00148                                         $subElemContent = null;
00149                                 }
00150 
00151                                 if ( isset( $elemValue['_element'] ) ) {
00152                                         $subElemIndName = $elemValue['_element'];
00153                                         unset( $elemValue['_element'] );
00154                                 } else {
00155                                         $subElemIndName = null;
00156                                 }
00157 
00158                                 $indElements = array();
00159                                 $subElements = array();
00160                                 foreach ( $elemValue as $subElemId => & $subElemValue ) {
00161                                         if ( is_string( $subElemValue ) && $doublequote ) {
00162                                                 $subElemValue = Sanitizer::encodeAttribute( $subElemValue );
00163                                         }
00164 
00165                                         if ( gettype( $subElemId ) === 'integer' ) {
00166                                                 $indElements[] = $subElemValue;
00167                                                 unset( $elemValue[$subElemId] );
00168                                         } elseif ( is_array( $subElemValue ) ) {
00169                                                 $subElements[$subElemId] = $subElemValue;
00170                                                 unset ( $elemValue[$subElemId] );
00171                                         }
00172                                 }
00173 
00174                                 if ( is_null( $subElemIndName ) && count( $indElements ) ) {
00175                                         ApiBase::dieDebug( __METHOD__, "($elemName, ...) has integer keys without _element value. Use ApiResult::setIndexedTagName()." );
00176                                 }
00177 
00178                                 if ( count( $subElements ) && count( $indElements ) && !is_null( $subElemContent ) ) {
00179                                         ApiBase::dieDebug( __METHOD__, "($elemName, ...) has content and subelements" );
00180                                 }
00181 
00182                                 if ( !is_null( $subElemContent ) ) {
00183                                         $retval .= $indstr . Xml::element( $elemName, $elemValue, $subElemContent );
00184                                 } elseif ( !count( $indElements ) && !count( $subElements ) ) {
00185                                         $retval .= $indstr . Xml::element( $elemName, $elemValue );
00186                                 } else {
00187                                         $retval .= $indstr . Xml::element( $elemName, $elemValue, null );
00188 
00189                                         foreach ( $subElements as $subElemId => & $subElemValue ) {
00190                                                 $retval .= self::recXmlPrint( $subElemId, $subElemValue, $indent );
00191                                         }
00192 
00193                                         foreach ( $indElements as &$subElemValue ) {
00194                                                 $retval .= self::recXmlPrint( $subElemIndName, $subElemValue, $indent );
00195                                         }
00196 
00197                                         $retval .= $indstr . Xml::closeElement( $elemName );
00198                                 }
00199                                 break;
00200                         case 'object':
00201                                 // ignore
00202                                 break;
00203                         default:
00204                                 // to make sure null value doesn't produce unclosed element,
00205                                 // which is what Xml::element( $elemName, null, null ) returns
00206                                 if ( $elemValue === null ) {
00207                                         $retval .= $indstr . Xml::element( $elemName );
00208                                 } else {
00209                                         $retval .= $indstr . Xml::element( $elemName, null, $elemValue );
00210                                 }
00211                                 break;
00212                 }
00213                 return $retval;
00214         }
00215 
00216         function addXslt() {
00217                 $nt = Title::newFromText( $this->mXslt );
00218                 if ( is_null( $nt ) || !$nt->exists() ) {
00219                         $this->setWarning( 'Invalid or non-existent stylesheet specified' );
00220                         return;
00221                 }
00222                 if ( $nt->getNamespace() != NS_MEDIAWIKI ) {
00223                         $this->setWarning( 'Stylesheet should be in the MediaWiki namespace.' );
00224                         return;
00225                 }
00226                 if ( substr( $nt->getText(), - 4 ) !== '.xsl' ) {
00227                         $this->setWarning( 'Stylesheet should have .xsl extension.' );
00228                         return;
00229                 }
00230                 $this->printText( '<?xml-stylesheet href="' . htmlspecialchars( $nt->getLocalURL( 'action=raw' ) ) . '" type="text/xsl" ?>' );
00231         }
00232 
00233         public function getAllowedParams() {
00234                 return array(
00235                         'xmldoublequote' => false,
00236                         'xslt' => null,
00237                         'includexmlnamespace' => false,
00238                 );
00239         }
00240 
00241         public function getParamDescription() {
00242                 return array(
00243                         'xmldoublequote' => 'If specified, double quotes all attributes and content',
00244                         'xslt' => 'If specified, adds <xslt> as stylesheet. This should be a wiki page '
00245                                 . 'in the MediaWiki namespace whose page name ends with ".xsl"',
00246                         'includexmlnamespace' => 'If specified, adds an XML namespace'
00247                 );
00248         }
00249 
00250         public function getDescription() {
00251                 return 'Output data in XML format' . parent::getDescription();
00252         }
00253 }