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