2015-04-27 14:05:31 +00:00
|
|
|
<?php
|
2018-08-09 09:49:10 +00:00
|
|
|
namespace PortableInfobox\Parser;
|
2015-04-27 14:05:31 +00:00
|
|
|
|
2018-07-24 13:56:43 +00:00
|
|
|
use MediaWiki\Logger\LoggerFactory;
|
2015-04-27 14:05:31 +00:00
|
|
|
|
2015-06-10 15:19:40 +00:00
|
|
|
class XmlParser {
|
2015-09-07 10:22:56 +00:00
|
|
|
protected static $contentTags = [ 'default', 'label', 'format', 'navigation', 'header' ];
|
|
|
|
|
2015-05-29 13:04:04 +00:00
|
|
|
/**
|
2015-06-10 15:19:40 +00:00
|
|
|
* @param string $xmlString XML to parse
|
|
|
|
*
|
2018-08-16 09:25:53 +00:00
|
|
|
* @param array &$errors this array will be filled with errors if any found
|
2015-06-10 15:19:40 +00:00
|
|
|
*
|
2015-05-29 13:04:04 +00:00
|
|
|
* @return \SimpleXMLElement
|
|
|
|
* @throws XmlMarkupParseErrorException
|
|
|
|
*/
|
2018-08-16 09:25:53 +00:00
|
|
|
public static function parseXmlString( $xmlString, &$errors = [] ) {
|
2015-05-29 13:04:04 +00:00
|
|
|
$global_libxml_setting = libxml_use_internal_errors();
|
|
|
|
libxml_use_internal_errors( true );
|
2015-07-06 16:15:29 +00:00
|
|
|
// support for html entities and single & char
|
2015-09-07 10:22:56 +00:00
|
|
|
$xml = simplexml_load_string( self::prepareXml( $xmlString ) );
|
2015-05-29 13:04:04 +00:00
|
|
|
$errors = libxml_get_errors();
|
|
|
|
libxml_use_internal_errors( $global_libxml_setting );
|
|
|
|
|
|
|
|
if ( $xml === false ) {
|
|
|
|
foreach ( $errors as $xmlerror ) {
|
2015-06-10 15:19:40 +00:00
|
|
|
self::logXmlParseError( $xmlerror->level, $xmlerror->code, trim( $xmlerror->message ) );
|
2015-05-29 13:04:04 +00:00
|
|
|
}
|
|
|
|
libxml_clear_errors();
|
2015-06-19 12:43:40 +00:00
|
|
|
throw new XmlMarkupParseErrorException( $errors );
|
2015-05-29 13:04:04 +00:00
|
|
|
}
|
2015-06-10 15:19:40 +00:00
|
|
|
|
2015-05-29 13:04:04 +00:00
|
|
|
return $xml;
|
|
|
|
}
|
|
|
|
|
2015-06-10 15:19:40 +00:00
|
|
|
protected static function logXmlParseError( $level, $code, $message ) {
|
2018-10-02 07:41:19 +00:00
|
|
|
LoggerFactory::getInstance( 'PortableInfobox' )->info( 'PortableInfobox XML Parser problem', [
|
|
|
|
'level' => $level,
|
|
|
|
'code' => $code,
|
|
|
|
'message' => $message
|
|
|
|
] );
|
2015-06-10 15:19:40 +00:00
|
|
|
}
|
|
|
|
|
2015-09-07 10:22:56 +00:00
|
|
|
/**
|
|
|
|
* @param string $xmlString
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
protected static function prepareXml( $xmlString ) {
|
|
|
|
foreach ( self::$contentTags as $tag ) {
|
|
|
|
// wrap content in CDATA for content tags
|
2018-10-02 07:41:19 +00:00
|
|
|
$xmlString = preg_replace(
|
|
|
|
'|(<' . $tag . '.*>)(.*)(</' . $tag . '>)|sU', '$1<![CDATA[$2]]>$3',
|
|
|
|
$xmlString
|
|
|
|
);
|
2015-09-07 10:22:56 +00:00
|
|
|
}
|
|
|
|
$decoded = str_replace( '&', '&', html_entity_decode( $xmlString ) );
|
|
|
|
|
|
|
|
return $decoded;
|
|
|
|
}
|
|
|
|
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
2015-05-08 12:04:18 +00:00
|
|
|
|
2018-10-02 07:41:19 +00:00
|
|
|
// phpcs:ignore Generic.Files.OneObjectStructurePerFile.MultipleFound
|
2015-05-08 12:04:18 +00:00
|
|
|
class XmlMarkupParseErrorException extends \Exception {
|
2015-06-10 12:51:07 +00:00
|
|
|
private $errors;
|
|
|
|
|
|
|
|
public function __construct( $errors ) {
|
|
|
|
$this->errors = $errors;
|
2015-07-06 16:15:29 +00:00
|
|
|
|
2015-06-10 12:51:07 +00:00
|
|
|
return parent::__construct();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getErrors() {
|
|
|
|
return $this->errors;
|
|
|
|
}
|
2015-05-21 18:38:33 +00:00
|
|
|
}
|