MediaWiki
REL1_21
|
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 }