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