[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/api/ -> ApiFormatXml.php (source)

   1  <?php
   2  /**
   3   *
   4   *
   5   * Created on Sep 19, 2006
   6   *
   7   * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
   8   *
   9   * This program is free software; you can redistribute it and/or modify
  10   * it under the terms of the GNU General Public License as published by
  11   * the Free Software Foundation; either version 2 of the License, or
  12   * (at your option) any later version.
  13   *
  14   * This program is distributed in the hope that it will be useful,
  15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17   * GNU General Public License for more details.
  18   *
  19   * You should have received a copy of the GNU General Public License along
  20   * with this program; if not, write to the Free Software Foundation, Inc.,
  21   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22   * http://www.gnu.org/copyleft/gpl.html
  23   *
  24   * @file
  25   */
  26  
  27  /**
  28   * API XML output formatter
  29   * @ingroup API
  30   */
  31  class ApiFormatXml extends ApiFormatBase {
  32  
  33      private $mRootElemName = 'api';
  34      public static $namespace = 'http://www.mediawiki.org/xml/api/';
  35      private $mIncludeNamespace = false;
  36      private $mXslt = null;
  37  
  38  	public function getMimeType() {
  39          return 'text/xml';
  40      }
  41  
  42  	public function getNeedsRawData() {
  43          return true;
  44      }
  45  
  46  	public function setRootElement( $rootElemName ) {
  47          $this->mRootElemName = $rootElemName;
  48      }
  49  
  50  	public function execute() {
  51          $params = $this->extractRequestParams();
  52          $this->mIncludeNamespace = $params['includexmlnamespace'];
  53          $this->mXslt = $params['xslt'];
  54  
  55          $this->printText( '<?xml version="1.0"?>' );
  56          if ( !is_null( $this->mXslt ) ) {
  57              $this->addXslt();
  58          }
  59          if ( $this->mIncludeNamespace ) {
  60              // If the result data already contains an 'xmlns' namespace added
  61              // for custom XML output types, it will override the one for the
  62              // generic API results.
  63              // This allows API output of other XML types like Atom, RSS, RSD.
  64              $data = $this->getResultData() + array( 'xmlns' => self::$namespace );
  65          } else {
  66              $data = $this->getResultData();
  67          }
  68  
  69          $this->printText(
  70              self::recXmlPrint( $this->mRootElemName,
  71                  $data,
  72                  $this->getIsHtml() ? -2 : null
  73              )
  74          );
  75      }
  76  
  77      /**
  78       * This method takes an array and converts it to XML.
  79       *
  80       * There are several noteworthy cases:
  81       *
  82       * If array contains a key '_element', then the code assumes that ALL
  83       * other keys are not important and replaces them with the
  84       * value['_element'].
  85       *
  86       * @par Example:
  87       * @verbatim
  88       * name='root', value = array( '_element'=>'page', 'x', 'y', 'z')
  89       * @endverbatim
  90       * creates:
  91       * @verbatim
  92       * <root>  <page>x</page>  <page>y</page>  <page>z</page> </root>
  93       * @endverbatim
  94       *
  95       * If any of the array's element key is '*', then the code treats all
  96       * other key->value pairs as attributes, and the value['*'] as the
  97       * element's content.
  98       *
  99       * @par Example:
 100       * @verbatim
 101       * name='root', value = array( '*'=>'text', 'lang'=>'en', 'id'=>10)
 102       * @endverbatim
 103       * creates:
 104       * @verbatim
 105       * <root lang='en' id='10'>text</root>
 106       * @endverbatim
 107       *
 108       * Finally neither key is found, all keys become element names, and values
 109       * become element content.
 110       *
 111       * @note The method is recursive, so the same rules apply to any
 112       * sub-arrays.
 113       *
 114       * @param string $elemName
 115       * @param mixed $elemValue
 116       * @param int $indent
 117       *
 118       * @return string
 119       */
 120  	public static function recXmlPrint( $elemName, $elemValue, $indent ) {
 121          $retval = '';
 122          if ( !is_null( $indent ) ) {
 123              $indent += 2;
 124              $indstr = "\n" . str_repeat( ' ', $indent );
 125          } else {
 126              $indstr = '';
 127          }
 128          $elemName = str_replace( ' ', '_', $elemName );
 129  
 130          if ( is_array( $elemValue ) ) {
 131              if ( isset( $elemValue['*'] ) ) {
 132                  $subElemContent = $elemValue['*'];
 133                  unset( $elemValue['*'] );
 134  
 135                  // Add xml:space="preserve" to the
 136                  // element so XML parsers will leave
 137                  // whitespace in the content alone
 138                  $elemValue['xml:space'] = 'preserve';
 139              } else {
 140                  $subElemContent = null;
 141              }
 142  
 143              if ( isset( $elemValue['_element'] ) ) {
 144                  $subElemIndName = $elemValue['_element'];
 145                  unset( $elemValue['_element'] );
 146              } else {
 147                  $subElemIndName = null;
 148              }
 149  
 150              if ( isset( $elemValue['_subelements'] ) ) {
 151                  foreach ( $elemValue['_subelements'] as $subElemId ) {
 152                      if ( isset( $elemValue[$subElemId] ) && !is_array( $elemValue[$subElemId] ) ) {
 153                          $elemValue[$subElemId] = array( '*' => $elemValue[$subElemId] );
 154                      }
 155                  }
 156                  unset( $elemValue['_subelements'] );
 157              }
 158  
 159              $indElements = array();
 160              $subElements = array();
 161              foreach ( $elemValue as $subElemId => & $subElemValue ) {
 162                  if ( is_int( $subElemId ) ) {
 163                      $indElements[] = $subElemValue;
 164                      unset( $elemValue[$subElemId] );
 165                  } elseif ( is_array( $subElemValue ) ) {
 166                      $subElements[$subElemId] = $subElemValue;
 167                      unset( $elemValue[$subElemId] );
 168                  } elseif ( is_bool( $subElemValue ) ) {
 169                      // treat true as empty string, skip false in xml format
 170                      if ( $subElemValue === true ) {
 171                          $subElemValue = '';
 172                      } else {
 173                          unset( $elemValue[$subElemId] );
 174                      }
 175                  }
 176              }
 177  
 178              if ( is_null( $subElemIndName ) && count( $indElements ) ) {
 179                  ApiBase::dieDebug( __METHOD__, "($elemName, ...) has integer keys " .
 180                      "without _element value. Use ApiResult::setIndexedTagName()." );
 181              }
 182  
 183              if ( count( $subElements ) && count( $indElements ) && !is_null( $subElemContent ) ) {
 184                  ApiBase::dieDebug( __METHOD__, "($elemName, ...) has content and subelements" );
 185              }
 186  
 187              if ( !is_null( $subElemContent ) ) {
 188                  $retval .= $indstr . Xml::element( $elemName, $elemValue, $subElemContent );
 189              } elseif ( !count( $indElements ) && !count( $subElements ) ) {
 190                  $retval .= $indstr . Xml::element( $elemName, $elemValue );
 191              } else {
 192                  $retval .= $indstr . Xml::element( $elemName, $elemValue, null );
 193  
 194                  foreach ( $subElements as $subElemId => & $subElemValue ) {
 195                      $retval .= self::recXmlPrint( $subElemId, $subElemValue, $indent );
 196                  }
 197  
 198                  foreach ( $indElements as &$subElemValue ) {
 199                      $retval .= self::recXmlPrint( $subElemIndName, $subElemValue, $indent );
 200                  }
 201  
 202                  $retval .= $indstr . Xml::closeElement( $elemName );
 203              }
 204          } elseif ( !is_object( $elemValue ) ) {
 205              // to make sure null value doesn't produce unclosed element,
 206              // which is what Xml::element( $elemName, null, null ) returns
 207              if ( $elemValue === null ) {
 208                  $retval .= $indstr . Xml::element( $elemName );
 209              } else {
 210                  $retval .= $indstr . Xml::element( $elemName, null, $elemValue );
 211              }
 212          }
 213  
 214          return $retval;
 215      }
 216  
 217  	function addXslt() {
 218          $nt = Title::newFromText( $this->mXslt );
 219          if ( is_null( $nt ) || !$nt->exists() ) {
 220              $this->setWarning( 'Invalid or non-existent stylesheet specified' );
 221  
 222              return;
 223          }
 224          if ( $nt->getNamespace() != NS_MEDIAWIKI ) {
 225              $this->setWarning( 'Stylesheet should be in the MediaWiki namespace.' );
 226  
 227              return;
 228          }
 229          if ( substr( $nt->getText(), -4 ) !== '.xsl' ) {
 230              $this->setWarning( 'Stylesheet should have .xsl extension.' );
 231  
 232              return;
 233          }
 234          $this->printText( '<?xml-stylesheet href="' .
 235              htmlspecialchars( $nt->getLocalURL( 'action=raw' ) ) . '" type="text/xsl" ?>' );
 236      }
 237  
 238  	public function getAllowedParams() {
 239          return array(
 240              'xslt' => null,
 241              'includexmlnamespace' => false,
 242          );
 243      }
 244  
 245  	public function getParamDescription() {
 246          return array(
 247              'xslt' => 'If specified, adds <xslt> as stylesheet. This should be a wiki page '
 248                  . 'in the MediaWiki namespace whose page name ends with ".xsl"',
 249              'includexmlnamespace' => 'If specified, adds an XML namespace'
 250          );
 251      }
 252  
 253  	public function getDescription() {
 254          return 'Output data in XML format' . parent::getDescription();
 255      }
 256  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1