diff --git a/src/Plugin/migrate_plus/data_parser/SimpleXml.php b/src/Plugin/migrate_plus/data_parser/SimpleXml.php new file mode 100644 index 0000000000000000000000000000000000000000..a526ecc2346155495472105b221df31769427629 --- /dev/null +++ b/src/Plugin/migrate_plus/data_parser/SimpleXml.php @@ -0,0 +1,76 @@ +<?php + +namespace Drupal\migrate_plus\Plugin\migrate_plus\data_parser; + +use Drupal\migrate\MigrateException; +use Drupal\migrate_plus\DataParserPluginBase; + +/** + * Obtain XML data for migration using the SimpleXML API. + * + * @DataParser( + * id = "simple_xml", + * title = @Translation("Simple XML") + * ) + */ +class SimpleXml extends DataParserPluginBase { + + use XmlTrait; + + /** + * Array of matches from item_selector. + * + * @var array + */ + protected $matches = []; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + // Suppress errors during parsing, so we can pick them up after. + libxml_use_internal_errors(TRUE); + } + + /** + * {@inheritdoc} + */ + protected function openSourceUrl($url) { + $xml_data = $this->getDataFetcherPlugin()->getResponseContent($url); + $xml = simplexml_load_string($xml_data); + $this->registerNamespaces($xml); + $xpath = $this->configuration['item_selector']; + $this->matches = $xml->xpath($xpath); + foreach (libxml_get_errors() as $error) { + $error_string = self::parseLibXmlError($error); + throw new MigrateException($error_string); + } + return TRUE; + } + + /** + * {@inheritdoc} + */ + protected function fetchNextRow() { + $target_element = array_shift($this->matches); + + // If we've found the desired element, populate the currentItem and + // currentId with its data. + if ($target_element !== FALSE && !is_null($target_element)) { + foreach ($this->fieldSelectors() as $field_name => $xpath) { + foreach ($target_element->xpath($xpath) as $value) { + $this->currentItem[$field_name][] = (string) $value; + } + } + // Reduce single-value results to scalars. + foreach ($this->currentItem as $field_name => $values) { + if (count($values) == 1) { + $this->currentItem[$field_name] = reset($values); + } + } + } + } + +} diff --git a/src/Plugin/migrate_plus/data_parser/Xml.php b/src/Plugin/migrate_plus/data_parser/Xml.php index e552cb08e321fd54d416ad31903034127aed2bef..4592f7814b9ee112ae91d7d8db53ffed770fbfdb 100644 --- a/src/Plugin/migrate_plus/data_parser/Xml.php +++ b/src/Plugin/migrate_plus/data_parser/Xml.php @@ -2,19 +2,20 @@ namespace Drupal\migrate_plus\Plugin\migrate_plus\data_parser; -use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\migrate\MigrateException; use Drupal\migrate_plus\DataParserPluginBase; /** - * Obtain XML data for migration. + * Obtain XML data for migration using the XMLReader pull parser. * * @DataParser( * id = "xml", * title = @Translation("XML") * ) */ -class Xml extends DataParserPluginBase implements ContainerFactoryPluginInterface { +class Xml extends DataParserPluginBase { + + use XmlTrait; /** * The XMLReader we are encapsulating. @@ -293,59 +294,4 @@ class Xml extends DataParserPluginBase implements ContainerFactoryPluginInterfac } } - /** - * Registers the iterator's namespaces to a SimpleXMLElement. - * - * @param \SimpleXMLElement $xml - * The element to apply namespace registrations to. - */ - protected function registerNamespaces(\SimpleXMLElement $xml) { - if (isset($this->configuration['namespaces']) && is_array($this->configuration['namespaces'])) { - foreach ($this->configuration['namespaces'] as $prefix => $ns) { - $xml->registerXPathNamespace($prefix, $ns); - } - } - } - - /** - * Parses a LibXMLError to a error message string. - * - * @param \LibXMLError $error - * Error thrown by the XML. - * - * @return string - * Error message - */ - public static function parseLibXmlError(\LibXMLError $error) { - $error_code_name = 'Unknown Error'; - switch ($error->level) { - case LIBXML_ERR_WARNING: - $error_code_name = t('Warning'); - break; - - case LIBXML_ERR_ERROR: - $error_code_name = t('Error'); - break; - - case LIBXML_ERR_FATAL: - $error_code_name = t('Fatal Error'); - break; - } - - return t( - "@libxmlerrorcodename @libxmlerrorcode: @libxmlerrormessage\n" . - "Line: @libxmlerrorline\n" . - "Column: @libxmlerrorcolumn\n" . - "File: @libxmlerrorfile", - [ - '@libxmlerrorcodename' => $error_code_name, - '@libxmlerrorcode' => $error->code, - '@libxmlerrormessage' => trim($error->message), - '@libxmlerrorline' => $error->line, - '@libxmlerrorcolumn' => $error->column, - '@libxmlerrorfile' => (($error->file)) ? $error->file : NULL, - ] - ); - } - } diff --git a/src/Plugin/migrate_plus/data_parser/XmlTrait.php b/src/Plugin/migrate_plus/data_parser/XmlTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..25af9b6d46a0fb33564180fe052997081ab0bfc3 --- /dev/null +++ b/src/Plugin/migrate_plus/data_parser/XmlTrait.php @@ -0,0 +1,65 @@ +<?php + +namespace Drupal\migrate_plus\Plugin\migrate_plus\data_parser; + +/** + * Common functionality for XML data parsers. + */ +trait XmlTrait { + + /** + * Registers the iterator's namespaces to a SimpleXMLElement. + * + * @param \SimpleXMLElement $xml + * The element to apply namespace registrations to. + */ + protected function registerNamespaces(\SimpleXMLElement $xml) { + if (is_array($this->configuration['namespaces'])) { + foreach ($this->configuration['namespaces'] as $prefix => $ns) { + $xml->registerXPathNamespace($prefix, $ns); + } + } + } + + /** + * Parses a LibXMLError to a error message string. + * + * @param \LibXMLError $error + * Error thrown by the XML. + * + * @return string + * Error message + */ + public static function parseLibXmlError(\LibXMLError $error) { + $error_code_name = 'Unknown Error'; + switch ($error->level) { + case LIBXML_ERR_WARNING: + $error_code_name = t('Warning'); + break; + + case LIBXML_ERR_ERROR: + $error_code_name = t('Error'); + break; + + case LIBXML_ERR_FATAL: + $error_code_name = t('Fatal Error'); + break; + } + + return t( + "@libxmlerrorcodename @libxmlerrorcode: @libxmlerrormessage\n" . + "Line: @libxmlerrorline\n" . + "Column: @libxmlerrorcolumn\n" . + "File: @libxmlerrorfile", + [ + '@libxmlerrorcodename' => $error_code_name, + '@libxmlerrorcode' => $error->code, + '@libxmlerrormessage' => trim($error->message), + '@libxmlerrorline' => $error->line, + '@libxmlerrorcolumn' => $error->column, + '@libxmlerrorfile' => (($error->file)) ? $error->file : NULL, + ] + ); + } + +}