X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fapi%2FApiFormatXml.php;h=ef2c54f59e9f226410d27d99360a88594e352a34;hb=cf0fc6e4a060b4846c5594b006751b41a66fb849;hp=b27763b6ade2a4a15d2574da564dec344101e07f;hpb=8a7397e8ad87d871f30a1936d4231613b464fbe5;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/api/ApiFormatXml.php b/includes/api/ApiFormatXml.php index b27763b6ad..ef2c54f59e 100644 --- a/includes/api/ApiFormatXml.php +++ b/includes/api/ApiFormatXml.php @@ -1,12 +1,10 @@ + * Created on Sep 19, 2006 + * + * Copyright © 2006 Yuri Astrakhan @gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,113 +18,214 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html + * + * @file */ -if (!defined('MEDIAWIKI')) { - // Eclipse helper - will be ignored in production - require_once ("ApiFormatBase.php"); -} - +/** + * API XML output formatter + * @ingroup API + */ class ApiFormatXml extends ApiFormatBase { - public function __construct($main, $format) { - parent :: __construct($main, $format); + private $mRootElemName = 'api'; + public static $namespace = 'http://www.mediawiki.org/xml/api/'; + private $mDoubleQuote = false; + private $mIncludeNamespace = false; + private $mXslt = null; + + public function __construct( $main, $format ) { + parent::__construct( $main, $format ); } - public function GetMimeType() { + public function getMimeType() { return 'text/xml'; } - public function GetNeedsRawData() { + public function getNeedsRawData() { return true; } - public function Execute() { - $xmlindent = null; - extract($this->ExtractRequestParams()); + public function setRootElement( $rootElemName ) { + $this->mRootElemName = $rootElemName; + } + + public function execute() { + $params = $this->extractRequestParams(); + $this->mDoubleQuote = $params['xmldoublequote']; + $this->mIncludeNamespace = $params['includexmlnamespace']; + $this->mXslt = $params['xslt']; - if ($xmlindent || $this->GetIsHtml()) - $xmlindent = -2; - else - $xmlindent = null; + $this->printText( '' ); + if ( !is_null( $this->mXslt ) ) { + $this->addXslt(); + } + if ( $this->mIncludeNamespace ) { + // If the result data already contains an 'xmlns' namespace added + // for custom XML output types, it will override the one for the + // generic API results. + // This allows API output of other XML types like Atom, RSS, RSD. + $data = $this->getResultData() + array( 'xmlns' => self::$namespace ); + } else { + $data = $this->getResultData(); + } - $this->PrintText(''); - $this->recXmlPrint('api', $this->GetResult()->GetData(), $xmlindent); + $this->printText( + self::recXmlPrint( $this->mRootElemName, + $data, + $this->getIsHtml() ? - 2 : null, + $this->mDoubleQuote + ) + ); } /** - * This method takes an array and converts it into an xml. - * There are several noteworthy cases: - * - * If array contains a key "_element", then the code assumes that ALL other keys are not important and replaces them with the value['_element']. - * Example: name="root", value = array( "_element"=>"page", "x", "y", "z") creates x y z - * - * If any of the array's element key is "*", then the code treats all other key->value pairs as attributes, and the value['*'] as the element's content. - * Example: name="root", value = array( "*"=>"text", "lang"=>"en", "id"=>10) creates text - * - * If neither key is found, all keys become element names, and values become element content. - * The method is recursive, so the same rules apply to any sub-arrays. - */ - function recXmlPrint($elemName, $elemValue, $indent) { - $indstr = ""; - if (!is_null($indent)) { + * This method takes an array and converts it to XML. + * There are several noteworthy cases: + * + * If array contains a key '_element', then the code assumes that ALL other keys are not important and replaces them with the value['_element']. + * Example: name='root', value = array( '_element'=>'page', 'x', 'y', 'z') creates x y z + * + * If any of the array's element key is '*', then the code treats all other key->value pairs as attributes, and the value['*'] as the element's content. + * Example: name='root', value = array( '*'=>'text', 'lang'=>'en', 'id'=>10) creates text + * + * If neither key is found, all keys become element names, and values become element content. + * The method is recursive, so the same rules apply to any sub-arrays. + * + * @param $elemName + * @param $elemValue + * @param $indent + * @param $doublequote bool + * + * @return string + */ + public static function recXmlPrint( $elemName, $elemValue, $indent, $doublequote = false ) { + $retval = ''; + if ( !is_null( $indent ) ) { $indent += 2; - $indstr = "\n" . str_repeat(" ", $indent); + $indstr = "\n" . str_repeat( ' ', $indent ); + } else { + $indstr = ''; } + $elemName = str_replace( ' ', '_', $elemName ); - switch (gettype($elemValue)) { - case 'array' : - if (array_key_exists('*', $elemValue)) { + switch ( gettype( $elemValue ) ) { + case 'array': + if ( isset( $elemValue['*'] ) ) { $subElemContent = $elemValue['*']; - unset ($elemValue['*']); - if (gettype($subElemContent) === 'array') { - $this->PrintText($indstr . wfElement($elemName, $elemValue, null)); - $this->recXmlPrint($elemName, $subElemContent, $indent); - $this->PrintText($indstr . ""); - } else { - $this->PrintText($indstr . wfElement($elemName, $elemValue, $subElemContent)); + if ( $doublequote ) { + $subElemContent = Sanitizer::encodeAttribute( $subElemContent ); } + unset( $elemValue['*'] ); + + // Add xml:space="preserve" to the + // element so XML parsers will leave + // whitespace in the content alone + $elemValue['xml:space'] = 'preserve'; } else { - $this->PrintText($indstr . wfElement($elemName, null, null)); - if (array_key_exists('_element', $elemValue)) { - $subElemName = $elemValue['_element']; - foreach ($elemValue as $subElemId => & $subElemValue) { - if ($subElemId !== '_element') { - $this->recXmlPrint($subElemName, $subElemValue, $indent); - } - } - } else { - foreach ($elemValue as $subElemName => & $subElemValue) { - $this->recXmlPrint($subElemName, $subElemValue, $indent); - } + $subElemContent = null; + } + + if ( isset( $elemValue['_element'] ) ) { + $subElemIndName = $elemValue['_element']; + unset( $elemValue['_element'] ); + } else { + $subElemIndName = null; + } + + $indElements = array(); + $subElements = array(); + foreach ( $elemValue as $subElemId => & $subElemValue ) { + if ( is_string( $subElemValue ) && $doublequote ) { + $subElemValue = Sanitizer::encodeAttribute( $subElemValue ); } - $this->PrintText($indstr . ""); + + if ( gettype( $subElemId ) === 'integer' ) { + $indElements[] = $subElemValue; + unset( $elemValue[$subElemId] ); + } elseif ( is_array( $subElemValue ) ) { + $subElements[$subElemId] = $subElemValue; + unset ( $elemValue[$subElemId] ); + } + } + + if ( is_null( $subElemIndName ) && count( $indElements ) ) { + ApiBase::dieDebug( __METHOD__, "($elemName, ...) has integer keys without _element value. Use ApiResult::setIndexedTagName()." ); + } + + if ( count( $subElements ) && count( $indElements ) && !is_null( $subElemContent ) ) { + ApiBase::dieDebug( __METHOD__, "($elemName, ...) has content and subelements" ); + } + + if ( !is_null( $subElemContent ) ) { + $retval .= $indstr . Xml::element( $elemName, $elemValue, $subElemContent ); + } elseif ( !count( $indElements ) && !count( $subElements ) ) { + $retval .= $indstr . Xml::element( $elemName, $elemValue ); + } else { + $retval .= $indstr . Xml::element( $elemName, $elemValue, null ); + + foreach ( $subElements as $subElemId => & $subElemValue ) { + $retval .= self::recXmlPrint( $subElemId, $subElemValue, $indent ); + } + + foreach ( $indElements as &$subElemValue ) { + $retval .= self::recXmlPrint( $subElemIndName, $subElemValue, $indent ); + } + + $retval .= $indstr . Xml::closeElement( $elemName ); } break; - case 'object' : + case 'object': // ignore break; - default : - $this->PrintText($indstr . wfElement($elemName, null, $elemValue)); + default: + $retval .= $indstr . Xml::element( $elemName, null, $elemValue ); break; } + return $retval; } - protected function GetDescription() { - return 'Output data in XML format'; + + function addXslt() { + $nt = Title::newFromText( $this->mXslt ); + if ( is_null( $nt ) || !$nt->exists() ) { + $this->setWarning( 'Invalid or non-existent stylesheet specified' ); + return; + } + if ( $nt->getNamespace() != NS_MEDIAWIKI ) { + $this->setWarning( 'Stylesheet should be in the MediaWiki namespace.' ); + return; + } + if ( substr( $nt->getText(), - 4 ) !== '.xsl' ) { + $this->setWarning( 'Stylesheet should have .xsl extension.' ); + return; + } + $this->printText( 'getLocalURL( 'action=raw' ) ) . '" type="text/xsl" ?>' ); } - protected function GetAllowedParams() { - return array ( - 'xmlindent' => false + public function getAllowedParams() { + return array( + 'xmldoublequote' => false, + 'xslt' => null, + 'includexmlnamespace' => false, ); } - protected function GetParamDescription() { - return array ( - 'xmlindent' => 'Enable XML indentation' + public function getParamDescription() { + return array( + 'xmldoublequote' => 'If specified, double quotes all attributes and content', + 'xslt' => 'If specified, adds as stylesheet. This should be a wiki page ' + . 'in the MediaWiki namespace whose page name ends with ".xsl"', + 'includexmlnamespace' => 'If specified, adds an XML namespace' ); } + + public function getDescription() { + return 'Output data in XML format' . parent::getDescription(); + } + + public function getVersion() { + return __CLASS__ . ': $Id$'; + } } -?> \ No newline at end of file