MediaWiki master
Xml.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Xml;
10
14use UtfNormal\Validator;
15
19class Xml {
36 public static function element( $element, $attribs = null, $contents = '',
37 $allowShortTag = true
38 ) {
39 $out = '<' . $element;
40 if ( $attribs !== null ) {
41 $out .= self::expandAttributes( $attribs );
42 }
43 if ( $contents === null ) {
44 $out .= '>';
45 } elseif ( $allowShortTag && $contents === '' ) {
46 $out .= ' />';
47 } else {
48 // @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal $contents is non-nullable
49 $out .= '>' . htmlspecialchars( $contents, ENT_NOQUOTES ) . "</$element>";
50 }
51 return $out;
52 }
53
62 public static function expandAttributes( ?array $attribs ) {
63 if ( $attribs === null ) {
64 return null;
65 }
66 $out = '';
67 foreach ( $attribs as $name => $val ) {
68 $out .= " {$name}=\"" . Sanitizer::encodeAttribute( $val ) . '"';
69 }
70 return $out;
71 }
72
84 public static function elementClean( $element, $attribs = [], $contents = '' ) {
85 if ( $attribs ) {
86 $attribs = array_map( Validator::cleanUp( ... ), $attribs );
87 }
88 if ( $contents ) {
89 $contents =
90 MediaWikiServices::getInstance()->getContentLanguage()->normalize( $contents );
91 }
92 return self::element( $element, $attribs, $contents );
93 }
94
102 public static function openElement( $element, $attribs = null ) {
103 return '<' . $element . self::expandAttributes( $attribs ) . '>';
104 }
105
111 public static function closeElement( $element ) {
112 return "</$element>";
113 }
114
128 public static function tags( $element, $attribs, $contents ) {
129 return self::openElement( $element, $attribs ) . $contents . "</$element>";
130 }
131
142 public static function attrib( $name, $present = true ) {
143 return $present ? [ $name => $name ] : [];
144 }
145
158 public static function label( $label, $id, $attribs = [] ) {
159 $a = [ 'for' => $id ];
160
161 foreach ( [ 'class', 'title' ] as $attr ) {
162 if ( isset( $attribs[$attr] ) ) {
163 $a[$attr] = $attribs[$attr];
164 }
165 }
166
167 return self::element( 'label', $a, $label );
168 }
169
180 public static function option( $text, $value = null, $selected = false,
181 $attribs = [] ) {
182 if ( $value !== null ) {
183 $attribs['value'] = $value;
184 }
185 if ( $selected ) {
186 $attribs['selected'] = 'selected';
187 }
188 return Html::element( 'option', $attribs, $text );
189 }
190
206 public static function listDropdown( $name = '', $list = '', $other = '',
207 $selected = '', $class = '', $tabindex = null
208 ) {
209 $options = self::listDropdownOptions( $list, [ 'other' => $other ] );
210
211 $xmlSelect = new XmlSelect( $name, $name, $selected );
212 $xmlSelect->addOptions( $options );
213
214 if ( $class ) {
215 $xmlSelect->setAttribute( 'class', $class );
216 }
217 if ( $tabindex ) {
218 $xmlSelect->setAttribute( 'tabindex', $tabindex );
219 }
220
221 return $xmlSelect->getHTML();
222 }
223
239 public static function listDropdownOptions( $list, $params = [] ) {
240 $options = [];
241
242 if ( isset( $params['other'] ) ) {
243 $options[ $params['other'] ] = 'other';
244 }
245
246 $optgroup = false;
247 foreach ( explode( "\n", $list ) as $option ) {
248 $value = trim( $option );
249 if ( $value == '' ) {
250 continue;
251 }
252 if ( str_starts_with( $value, '*' ) && substr( $value, 1, 1 ) != '*' ) {
253 # A new group is starting...
254 $value = trim( substr( $value, 1 ) );
255 if ( $value !== '' &&
256 // Do not use the value for 'other' as option group - T251351
257 ( !isset( $params['other'] ) || $value !== $params['other'] )
258 ) {
259 $optgroup = $value;
260 } else {
261 $optgroup = false;
262 }
263 } elseif ( str_starts_with( $value, '**' ) ) {
264 # groupmember
265 $opt = trim( substr( $value, 2 ) );
266 if ( $optgroup === false ) {
267 $options[$opt] = $opt;
268 } else {
269 $options[$optgroup][$opt] = $opt;
270 }
271 } else {
272 # groupless reason list
273 $optgroup = false;
274 $options[$option] = $option;
275 }
276 }
277
278 return $options;
279 }
280
291 public static function listDropdownOptionsOoui( $options ) {
292 $optionsOoui = [];
293
294 foreach ( $options as $text => $value ) {
295 if ( is_array( $value ) ) {
296 $optionsOoui[] = [ 'optgroup' => (string)$text ];
297 foreach ( $value as $text2 => $value2 ) {
298 $optionsOoui[] = [ 'data' => (string)$value2, 'label' => (string)$text2 ];
299 }
300 } else {
301 $optionsOoui[] = [ 'data' => (string)$value, 'label' => (string)$text ];
302 }
303 }
304
305 return $optionsOoui;
306 }
307
320 public static function fieldset( $legend = false, $content = false, $attribs = [] ) {
321 $s = self::openElement( 'fieldset', $attribs ) . "\n";
322
323 if ( $legend ) {
324 $s .= self::element( 'legend', null, $legend ) . "\n";
325 }
326
327 if ( $content !== false ) {
328 $s .= $content . "\n";
329 $s .= self::closeElement( 'fieldset' ) . "\n";
330 }
331
332 return $s;
333 }
334
346 private static function isWellFormed( $text ) {
347 $parser = xml_parser_create( "UTF-8" );
348
349 # case folding violates XML standard, turn it off
350 xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 );
351
352 if ( !xml_parse( $parser, $text, true ) ) {
353 return false;
354 }
355 return true;
356 }
357
366 public static function isWellFormedXmlFragment( $text ) {
367 $html =
368 Sanitizer::hackDocType() .
369 '<html>' .
370 $text .
371 '</html>';
372
373 return self::isWellFormed( $html );
374 }
375
383 public static function escapeTagsOnly( $in ) {
384 return str_replace(
385 [ '"', '>', '<' ],
386 [ '&quot;', '&gt;', '&lt;' ],
387 $in );
388 }
389
403 public static function buildForm( $fields, $submitLabel = null, $submitAttribs = [] ) {
404 $form = '';
405 $form .= "<table><tbody>";
406
407 foreach ( $fields as $labelmsg => $input ) {
408 $id = "mw-$labelmsg";
409 $form .= self::openElement( 'tr', [ 'id' => $id ] );
410
411 // TODO use a <label> here for accessibility purposes - will need
412 // to either not use a table to build the form, or find the ID of
413 // the input somehow.
414
415 $form .= self::tags( 'td', [ 'class' => 'mw-label' ], wfMessage( $labelmsg )->parse() );
416 $form .= self::openElement( 'td', [ 'class' => 'mw-input' ] )
417 . $input . self::closeElement( 'td' );
418 $form .= self::closeElement( 'tr' );
419 }
420
421 if ( $submitLabel ) {
422 $form .= self::openElement( 'tr' );
423 $form .= self::tags( 'td', [], '' );
424 $form .= self::openElement( 'td', [ 'class' => 'mw-submit' ] )
426 'input',
427 $submitAttribs + [
428 'type' => 'submit',
429 'value' => wfMessage( $submitLabel )->text(),
430 ]
431 )
432 . self::closeElement( 'td' );
433 $form .= self::closeElement( 'tr' );
434 }
435
436 $form .= "</tbody></table>";
437
438 return $form;
439 }
440}
442class_alias( Xml::class, 'Xml' );
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
This class is a collection of static functions that serve two purposes:
Definition Html.php:43
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:32
Class for generating HTML <select> or <datalist> elements.
Definition XmlSelect.php:16
Module of static functions for generating XML.
Definition Xml.php:19
static escapeTagsOnly( $in)
Replace " > and < with their respective HTML entities ( ", >, <)
Definition Xml.php:383
static elementClean( $element, $attribs=[], $contents='')
Format an XML element as with self::element(), but run text through the content language's normalize(...
Definition Xml.php:84
static attrib( $name, $present=true)
Internal function for use in checkboxes and radio buttons and such.
Definition Xml.php:142
static isWellFormedXmlFragment( $text)
Check if a string is a well-formed XML fragment.
Definition Xml.php:366
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition Xml.php:36
static label( $label, $id, $attribs=[])
Convenience function to build an HTML form label.
Definition Xml.php:158
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition Xml.php:128
static expandAttributes(?array $attribs)
Given an array of ('attributename' => 'value'), it generates the code to set the XML attributes : att...
Definition Xml.php:62
static buildForm( $fields, $submitLabel=null, $submitAttribs=[])
Generate a form (without the opening form element).
Definition Xml.php:403
static openElement( $element, $attribs=null)
This opens an XML element.
Definition Xml.php:102
static option( $text, $value=null, $selected=false, $attribs=[])
Convenience function to build an HTML drop-down list item.
Definition Xml.php:180
static listDropdown( $name='', $list='', $other='', $selected='', $class='', $tabindex=null)
Build a drop-down box from a textual list.
Definition Xml.php:206
static listDropdownOptionsOoui( $options)
Convert options for a drop-down box into a format accepted by OOUI\DropdownInputWidget etc.
Definition Xml.php:291
static closeElement( $element)
Shortcut to close an XML element.
Definition Xml.php:111
static fieldset( $legend=false, $content=false, $attribs=[])
Shortcut for creating fieldsets.
Definition Xml.php:320
static listDropdownOptions( $list, $params=[])
Build options for a drop-down box from a textual list.
Definition Xml.php:239
element(SerializerNode $parent, SerializerNode $node, $contents)