MediaWiki  REL1_19
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 
00104         public static function recXmlPrint( $elemName, $elemValue, $indent, $doublequote = false ) {
00105                 $retval = '';
00106                 if ( !is_null( $indent ) ) {
00107                         $indent += 2;
00108                         $indstr = "\n" . str_repeat( ' ', $indent );
00109                 } else {
00110                         $indstr = '';
00111                 }
00112                 $elemName = str_replace( ' ', '_', $elemName );
00113 
00114                 switch ( gettype( $elemValue ) ) {
00115                         case 'array':
00116                                 if ( isset( $elemValue['*'] ) ) {
00117                                         $subElemContent = $elemValue['*'];
00118                                         if ( $doublequote ) {
00119                                                 $subElemContent = Sanitizer::encodeAttribute( $subElemContent );
00120                                         }
00121                                         unset( $elemValue['*'] );
00122 
00123                                         // Add xml:space="preserve" to the
00124                                         // element so XML parsers will leave
00125                                         // whitespace in the content alone
00126                                         $elemValue['xml:space'] = 'preserve';
00127                                 } else {
00128                                         $subElemContent = null;
00129                                 }
00130 
00131                                 if ( isset( $elemValue['_element'] ) ) {
00132                                         $subElemIndName = $elemValue['_element'];
00133                                         unset( $elemValue['_element'] );
00134                                 } else {
00135                                         $subElemIndName = null;
00136                                 }
00137 
00138                                 $indElements = array();
00139                                 $subElements = array();
00140                                 foreach ( $elemValue as $subElemId => & $subElemValue ) {
00141                                         if ( is_string( $subElemValue ) && $doublequote ) {
00142                                                 $subElemValue = Sanitizer::encodeAttribute( $subElemValue );
00143                                         }
00144 
00145                                         if ( gettype( $subElemId ) === 'integer' ) {
00146                                                 $indElements[] = $subElemValue;
00147                                                 unset( $elemValue[$subElemId] );
00148                                         } elseif ( is_array( $subElemValue ) ) {
00149                                                 $subElements[$subElemId] = $subElemValue;
00150                                                 unset ( $elemValue[$subElemId] );
00151                                         }
00152                                 }
00153 
00154                                 if ( is_null( $subElemIndName ) && count( $indElements ) ) {
00155                                         ApiBase::dieDebug( __METHOD__, "($elemName, ...) has integer keys without _element value. Use ApiResult::setIndexedTagName()." );
00156                                 }
00157 
00158                                 if ( count( $subElements ) && count( $indElements ) && !is_null( $subElemContent ) ) {
00159                                         ApiBase::dieDebug( __METHOD__, "($elemName, ...) has content and subelements" );
00160                                 }
00161 
00162                                 if ( !is_null( $subElemContent ) ) {
00163                                         $retval .= $indstr . Xml::element( $elemName, $elemValue, $subElemContent );
00164                                 } elseif ( !count( $indElements ) && !count( $subElements ) ) {
00165                                         $retval .= $indstr . Xml::element( $elemName, $elemValue );
00166                                 } else {
00167                                         $retval .= $indstr . Xml::element( $elemName, $elemValue, null );
00168 
00169                                         foreach ( $subElements as $subElemId => & $subElemValue ) {
00170                                                 $retval .= self::recXmlPrint( $subElemId, $subElemValue, $indent );
00171                                         }
00172 
00173                                         foreach ( $indElements as &$subElemValue ) {
00174                                                 $retval .= self::recXmlPrint( $subElemIndName, $subElemValue, $indent );
00175                                         }
00176 
00177                                         $retval .= $indstr . Xml::closeElement( $elemName );
00178                                 }
00179                                 break;
00180                         case 'object':
00181                                 // ignore
00182                                 break;
00183                         default:
00184                                 $retval .= $indstr . Xml::element( $elemName, null, $elemValue );
00185                                 break;
00186                 }
00187                 return $retval;
00188         }
00189 
00190         function addXslt() {
00191                 $nt = Title::newFromText( $this->mXslt );
00192                 if ( is_null( $nt ) || !$nt->exists() ) {
00193                         $this->setWarning( 'Invalid or non-existent stylesheet specified' );
00194                         return;
00195                 }
00196                 if ( $nt->getNamespace() != NS_MEDIAWIKI ) {
00197                         $this->setWarning( 'Stylesheet should be in the MediaWiki namespace.' );
00198                         return;
00199                 }
00200                 if ( substr( $nt->getText(), - 4 ) !== '.xsl' ) {
00201                         $this->setWarning( 'Stylesheet should have .xsl extension.' );
00202                         return;
00203                 }
00204                 $this->printText( '<?xml-stylesheet href="' . htmlspecialchars( $nt->getLocalURL( 'action=raw' ) ) . '" type="text/xsl" ?>' );
00205         }
00206 
00207         public function getAllowedParams() {
00208                 return array(
00209                         'xmldoublequote' => false,
00210                         'xslt' => null,
00211                         'includexmlnamespace' => false,
00212                 );
00213         }
00214 
00215         public function getParamDescription() {
00216                 return array(
00217                         'xmldoublequote' => 'If specified, double quotes all attributes and content',
00218                         'xslt' => 'If specified, adds <xslt> as stylesheet',
00219                         'includexmlnamespace' => 'If specified, adds an XML namespace'
00220                 );
00221         }
00222 
00223         public function getDescription() {
00224                 return 'Output data in XML format' . parent::getDescription();
00225         }
00226 
00227         public function getVersion() {
00228                 return __CLASS__ . ': $Id$';
00229         }
00230 }