diff --git a/src/Plugin/migrate_plus/data_parser/SimpleXml.php b/src/Plugin/migrate_plus/data_parser/SimpleXml.php index 8a58d8b075c5d2bf77ed7a2ef634e54e0e1b0699..5e09822287d97f89faeccea88458bea22f6f6371 100644 --- a/src/Plugin/migrate_plus/data_parser/SimpleXml.php +++ b/src/Plugin/migrate_plus/data_parser/SimpleXml.php @@ -45,14 +45,14 @@ class SimpleXml extends DataParserPluginBase { libxml_clear_errors(); $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); + $xml = simplexml_load_string(trim($xml_data)); foreach (libxml_get_errors() as $error) { $error_string = self::parseLibXmlError($error); throw new MigrateException($error_string); } + $this->registerNamespaces($xml); + $xpath = $this->configuration['item_selector']; + $this->matches = $xml->xpath($xpath); return TRUE; } diff --git a/tests/data/simple_xml_broken_missing_tag.xml b/tests/data/simple_xml_broken_missing_tag.xml new file mode 100644 index 0000000000000000000000000000000000000000..75fe95fb79040c5395ce9c2ae5b9e9e96480d705 --- /dev/null +++ b/tests/data/simple_xml_broken_missing_tag.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<items> + <item id="1"> + <values title="Values"> + <value>Value 1</value> + <value>Value 2</value> + </values> + <!-- item --> + <item id="2"> + <values title="Values"> + <value>Value 1 (single)</value> + </values> + </item> +</items> diff --git a/tests/data/simple_xml_broken_tag_mismatch.xml b/tests/data/simple_xml_broken_tag_mismatch.xml new file mode 100644 index 0000000000000000000000000000000000000000..579540925dbb83420134dde3bc98306c83722c5c --- /dev/null +++ b/tests/data/simple_xml_broken_tag_mismatch.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- unmatched tags --> +<ietems> <!-- wrong tag --> + <item id="1"> + <values title="Values"> + <value>Value 1</value> + <value>Value 2</value> + </values> + </item> + <item id="2"> + <values title="Values"> + <value>Value 1 (single)</value> + </values> + </item> +</items> diff --git a/tests/data/simple_xml_invalid_multi_whitespace.xml b/tests/data/simple_xml_invalid_multi_whitespace.xml new file mode 100644 index 0000000000000000000000000000000000000000..a063482ca716569ee17fbf73c766e5a931904f75 --- /dev/null +++ b/tests/data/simple_xml_invalid_multi_whitespace.xml @@ -0,0 +1,17 @@ + + + +<?xml version="1.0" encoding="utf-8"?> +<items> + <item id="1"> + <values title="Values"> + <value>Value 1</value> + <value>Value 2</value> + </values> + </item> + <item id="2"> + <values title="Values"> + <value>Value 1 (single)</value> + </values> + </item> +</items> diff --git a/tests/data/simple_xml_invalid_single_line.xml b/tests/data/simple_xml_invalid_single_line.xml new file mode 100644 index 0000000000000000000000000000000000000000..86ec1961a50834163a9be7d884090d7b2b5c3327 --- /dev/null +++ b/tests/data/simple_xml_invalid_single_line.xml @@ -0,0 +1,15 @@ + +<?xml version="1.0" encoding="utf-8"?> +<items> + <item id="1"> + <values title="Values"> + <value>Value 1</value> + <value>Value 2</value> + </values> + </item> + <item id="2"> + <values title="Values"> + <value>Value 1 (single)</value> + </values> + </item> +</items> diff --git a/tests/data/simple_xml_non_xml.xml b/tests/data/simple_xml_non_xml.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7447b68393f618d3fd33494f5e83f1f61e8749f --- /dev/null +++ b/tests/data/simple_xml_non_xml.xml @@ -0,0 +1,17 @@ + + + +<? xml version="1.0" encoding="utf-8"?> +<items> + <item id="1"> + <values title="Values"> + <value>Value 1</value> + <value>Value 2</value> + </values> + </item> + <item id="2"> + <values title="Values"> + <value>Value 1 (single)</value> + </values> + </item> +</items> diff --git a/tests/src/Kernel/Plugin/migrate_plus/data_parser/SimpleXmlTest.php b/tests/src/Kernel/Plugin/migrate_plus/data_parser/SimpleXmlTest.php index fe6b345e1dfd53383924f7cf0b4ded3e75203ccc..6d0fcb3eea946675990a67dfd6eb484d3c865450 100644 --- a/tests/src/Kernel/Plugin/migrate_plus/data_parser/SimpleXmlTest.php +++ b/tests/src/Kernel/Plugin/migrate_plus/data_parser/SimpleXmlTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\migrate_plus\Kernel\Plugin\migrate_plus\data_parser; +use Drupal\Migrate\MigrateException; use Drupal\KernelTests\KernelTestBase; /** @@ -11,30 +12,54 @@ use Drupal\KernelTests\KernelTestBase; */ class SimpleXmlTest extends KernelTestBase { - public static $modules = ['migrate', 'migrate_plus']; + /** + * {@inheritdoc} + */ + protected static $modules = ['migrate', 'migrate_plus']; /** - * Tests reducing single values. + * Path for the xml file. * - * @throws \Drupal\Component\Plugin\Exception\PluginException - * @throws \Exception + * @var string */ - public function testReduceSingleValue() { - $path = $this->container - ->get('module_handler') - ->getModule('migrate_plus') - ->getPath(); - $url = $path . '/tests/data/simple_xml_reduce_single_value.xml'; - - /** @var \Drupal\migrate_plus\DataParserPluginManager $plugin_manager */ - $plugin_manager = $this->container + protected $path; + + /** + * The plugin manager. + * + * @var \Drupal\migrate_plus\DataParserPluginManager + */ + protected $pluginManager; + + /** + * The plugin configuration. + * + * @var array + */ + protected $configuration; + + /** + * The expected result. + * + * @var array + */ + protected $expected; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->path = $this->container->get('module_handler') + ->getModule('migrate_plus')->getPath(); + $this->pluginManager = $this->container ->get('plugin.manager.migrate_plus.data_parser'); - $conf = [ + $this->configuration = [ 'plugin' => 'url', 'data_fetcher_plugin' => 'file', 'data_parser_plugin' => 'simple_xml', 'destination' => 'node', - 'urls' => [$url], + 'urls' => [], 'ids' => ['id' => ['type' => 'integer']], 'fields' => [ [ @@ -50,18 +75,7 @@ class SimpleXmlTest extends KernelTestBase { ], 'item_selector' => '/items/item', ]; - $parser = $plugin_manager->createInstance('simple_xml', $conf); - - $data = []; - foreach ($parser as $item) { - $values = []; - foreach ($item['values'] as $value) { - $values[] = (string) $value; - } - $data[] = $values; - } - - $expected = [ + $this->expected = [ [ 'Value 1', 'Value 2', @@ -70,7 +84,120 @@ class SimpleXmlTest extends KernelTestBase { 'Value 1 (single)', ], ]; + } + + /** + * Tests reducing single values. + */ + public function testReduceSingleValue() { + $url = $this->path . '/tests/data/simple_xml_reduce_single_value.xml'; + $this->configuration['urls'][0] = $url; + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + + /** + * Test reading non standard conforming XML. + * + * XML file with lots of different white spaces before the starting tag. + */ + public function testReadNonStandardXmlWhitespace() { + $url = $this->path . '/tests/data/simple_xml_invalid_multi_whitespace.xml'; + $this->configuration['urls'][0] = $url; + + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + /** + * Test reading non standard conforming XML . + * + * XML file with one empty line before the starting tag. + */ + public function testReadNonStandardXml2() { + $url = $this->path . '/tests/data/simple_xml_invalid_single_line.xml'; + $this->configuration['urls'][0] = $url; + + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + + /** + * Test reading broken XML (missing closing tag). + * + * @throws \Drupal\Migrate\MigrateException + */ + public function testReadBrokenXmlMissingTag() { + $url = $this->path . '/tests/data/simple_xml_broken_missing_tag.xml'; + $this->configuration['urls'][0] = $url; + + $this->setExpectedException(MigrateException::class); + $this->expectExceptionMessageRegExp('/^Fatal Error 73/'); + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + + /** + * Test reading broken XML (tag mismatch). + * + * @throws \Drupal\Migrate\MigrateException + */ + public function testReadBrokenXmlTagMismatch() { + $url = $this->path . '/tests/data/simple_xml_broken_tag_mismatch.xml'; + $this->configuration['urls'][0] = $url; + + $this->setExpectedException(MigrateException::class); + $this->expectExceptionMessageRegExp('/^Fatal Error 76/'); + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + + /** + * Test reading non XML. + * + * @throws \Drupal\Migrate\MigrateException + */ + public function testReadNonXml() { + $url = $this->path . '/tests/data/simple_xml_non_xml.xml'; + $this->configuration['urls'][0] = $url; + + $this->setExpectedException(MigrateException::class); + $this->expectExceptionMessageRegExp('/^Fatal Error 46/'); + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + + /** + * Tests reading non-existing XML. + * + * @throws \Drupal\Migrate\MigrateException + */ + public function testReadNonExistingXml() { + $url = $this->path . '/tests/data/simple_xml_non_existing.xml'; + $this->configuration['urls'][0] = $url; + + $this->setExpectedException(MigrateException::class, 'file parser plugin: could not retrieve data from modules/migrate_plus/tests/data/simple_xml_non_existing.xml'); + $parser = $this->pluginManager->createInstance('simple_xml', $this->configuration); + $this->assertResults($this->expected, $parser); + } + + /** + * Parses and asserts the results match expectations. + * + * @param array|string $expected + * The expected results. + * @param \Traversable $parser + * An iterable data result to parse. + */ + protected function assertResults($expected, \Traversable $parser) { + $data = []; + foreach ($parser as $item) { + $values = []; + foreach ($item['values'] as $value) { + $values[] = (string) $value; + } + $data[] = $values; + } $this->assertEquals($expected, $data); }