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