]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/api/ApiFormatXml.php
MediaWiki 1.17.4
[autoinstalls/mediawiki.git] / includes / api / ApiFormatXml.php
1 <?php
2 /**
3  * API for MediaWiki 1.8+
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 if ( !defined( 'MEDIAWIKI' ) ) {
28         // Eclipse helper - will be ignored in production
29         require_once( 'ApiFormatBase.php' );
30 }
31
32 /**
33  * API XML output formatter
34  * @ingroup API
35  */
36 class ApiFormatXml extends ApiFormatBase {
37
38         private $mRootElemName = 'api';
39         private $mDoubleQuote = false;
40         private $mXslt = null;
41
42         public function __construct( $main, $format ) {
43                 parent::__construct( $main, $format );
44         }
45
46         public function getMimeType() {
47                 return 'text/xml';
48         }
49
50         public function getNeedsRawData() {
51                 return true;
52         }
53
54         public function setRootElement( $rootElemName ) {
55                 $this->mRootElemName = $rootElemName;
56         }
57
58         public function execute() {
59                 $params = $this->extractRequestParams();
60                 $this->mDoubleQuote = $params['xmldoublequote'];
61                 $this->mXslt = $params['xslt'];
62
63                 $this->printText( '<?xml version="1.0"?>' );
64                 if ( !is_null( $this->mXslt ) ) {
65                         $this->addXslt();
66                 }
67                 $this->printText(
68                         self::recXmlPrint( $this->mRootElemName,
69                                 $this->getResultData(),
70                                 $this->getIsHtml() ? - 2 : null,
71                                 $this->mDoubleQuote
72                         )
73                 );
74         }
75
76         /**
77          * This method takes an array and converts it to XML.
78          * There are several noteworthy cases:
79          *
80          *  If array contains a key '_element', then the code assumes that ALL other keys are not important and replaces them with the value['_element'].
81          *      Example:        name='root',  value = array( '_element'=>'page', 'x', 'y', 'z') creates <root>  <page>x</page>  <page>y</page>  <page>z</page> </root>
82          *
83          *  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.
84          *      Example:        name='root',  value = array( '*'=>'text', 'lang'=>'en', 'id'=>10)   creates  <root lang='en' id='10'>text</root>
85          *
86          * If neither key is found, all keys become element names, and values become element content.
87          * The method is recursive, so the same rules apply to any sub-arrays.
88          */
89         public static function recXmlPrint( $elemName, $elemValue, $indent, $doublequote = false ) {
90                 $retval = '';
91                 if ( !is_null( $indent ) ) {
92                         $indent += 2;
93                         $indstr = "\n" . str_repeat( ' ', $indent );
94                 } else {
95                         $indstr = '';
96                 }
97                 $elemName = str_replace( ' ', '_', $elemName );
98
99                 switch ( gettype( $elemValue ) ) {
100                         case 'array':
101                                 if ( isset( $elemValue['*'] ) ) {
102                                         $subElemContent = $elemValue['*'];
103                                         if ( $doublequote ) {
104                                                 $subElemContent = Sanitizer::encodeAttribute( $subElemContent );
105                                         }
106                                         unset( $elemValue['*'] );
107
108                                         // Add xml:space="preserve" to the
109                                         // element so XML parsers will leave
110                                         // whitespace in the content alone
111                                         $elemValue['xml:space'] = 'preserve';
112                                 } else {
113                                         $subElemContent = null;
114                                 }
115
116                                 if ( isset( $elemValue['_element'] ) ) {
117                                         $subElemIndName = $elemValue['_element'];
118                                         unset( $elemValue['_element'] );
119                                 } else {
120                                         $subElemIndName = null;
121                                 }
122
123                                 $indElements = array();
124                                 $subElements = array();
125                                 foreach ( $elemValue as $subElemId => & $subElemValue ) {
126                                         if ( is_string( $subElemValue ) && $doublequote ) {
127                                                 $subElemValue = Sanitizer::encodeAttribute( $subElemValue );
128                                         }
129
130                                         if ( gettype( $subElemId ) === 'integer' ) {
131                                                 $indElements[] = $subElemValue;
132                                                 unset( $elemValue[$subElemId] );
133                                         } elseif ( is_array( $subElemValue ) ) {
134                                                 $subElements[$subElemId] = $subElemValue;
135                                                 unset ( $elemValue[$subElemId] );
136                                         }
137                                 }
138
139                                 if ( is_null( $subElemIndName ) && count( $indElements ) ) {
140                                         ApiBase::dieDebug( __METHOD__, "($elemName, ...) has integer keys without _element value. Use ApiResult::setIndexedTagName()." );
141                                 }
142
143                                 if ( count( $subElements ) && count( $indElements ) && !is_null( $subElemContent ) ) {
144                                         ApiBase::dieDebug( __METHOD__, "($elemName, ...) has content and subelements" );
145                                 }
146
147                                 if ( !is_null( $subElemContent ) ) {
148                                         $retval .= $indstr . Xml::element( $elemName, $elemValue, $subElemContent );
149                                 } elseif ( !count( $indElements ) && !count( $subElements ) ) {
150                                         $retval .= $indstr . Xml::element( $elemName, $elemValue );
151                                 } else {
152                                         $retval .= $indstr . Xml::element( $elemName, $elemValue, null );
153
154                                         foreach ( $subElements as $subElemId => & $subElemValue ) {
155                                                 $retval .= self::recXmlPrint( $subElemId, $subElemValue, $indent );
156                                         }
157
158                                         foreach ( $indElements as &$subElemValue ) {
159                                                 $retval .= self::recXmlPrint( $subElemIndName, $subElemValue, $indent );
160                                         }
161
162                                         $retval .= $indstr . Xml::closeElement( $elemName );
163                                 }
164                                 break;
165                         case 'object':
166                                 // ignore
167                                 break;
168                         default:
169                                 $retval .= $indstr . Xml::element( $elemName, null, $elemValue );
170                                 break;
171                 }
172                 return $retval;
173         }
174
175         function addXslt() {
176                 $nt = Title::newFromText( $this->mXslt );
177                 if ( is_null( $nt ) || !$nt->exists() ) {
178                         $this->setWarning( 'Invalid or non-existent stylesheet specified' );
179                         return;
180                 }
181                 if ( $nt->getNamespace() != NS_MEDIAWIKI ) {
182                         $this->setWarning( 'Stylesheet should be in the MediaWiki namespace.' );
183                         return;
184                 }
185                 if ( substr( $nt->getText(), - 4 ) !== '.xsl' ) {
186                         $this->setWarning( 'Stylesheet should have .xsl extension.' );
187                         return;
188                 }
189                 $this->printText( '<?xml-stylesheet href="' . $nt->escapeLocalURL( 'action=raw' ) . '" type="text/xsl" ?>' );
190         }
191
192         public function getAllowedParams() {
193                 return array(
194                         'xmldoublequote' => false,
195                         'xslt' => null,
196                 );
197         }
198
199         public function getParamDescription() {
200                 return array(
201                         'xmldoublequote' => 'If specified, double quotes all attributes and content',
202                         'xslt' => 'If specified, adds <xslt> as stylesheet',
203                 );
204         }
205
206         public function getDescription() {
207                 return 'Output data in XML format' . parent::getDescription();
208         }
209
210         public function getVersion() {
211                 return __CLASS__ . ': $Id$';
212         }
213 }