From f6760d38996f5fbd3904285f345b22a74748b279 Mon Sep 17 00:00:00 2001 From: James Sansbury Date: Wed, 7 Mar 2018 08:51:08 -0500 Subject: [PATCH] [Serializer] Ignore comments when decoding XML --- UPGRADE-4.1.md | 5 ++ src/Symfony/Component/Serializer/CHANGELOG.md | 2 + .../Serializer/Encoder/XmlEncoder.php | 11 ++-- .../Tests/Encoder/XmlEncoderTest.php | 56 +++++++++++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/UPGRADE-4.1.md b/UPGRADE-4.1.md index d76e3a379618..e197d7bcc006 100644 --- a/UPGRADE-4.1.md +++ b/UPGRADE-4.1.md @@ -74,6 +74,11 @@ SecurityBundle * The `SecurityUserValueResolver` class is deprecated, use `Symfony\Component\Security\Http\Controller\UserValueResolver` instead. +Serializer +---------- + + * Decoding XML with `XmlEncoder` now ignores comment node types by default. + Translation ----------- diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index a4e8bf499f5c..d45e771e610b 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -11,6 +11,8 @@ CHANGELOG * added optional `bool $escapeFormulas = false` argument to `CsvEncoder::__construct` * added `AbstractObjectNormalizer::setMaxDepthHandler` to set a handler to call when the configured maximum depth is reached +* added optional `int[] $ignoredNodeTypes` argument to `XmlEncoder::__construct`. XML decoding now + ignores comment node types by default. 4.0.0 ----- diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php index fec0fefd08ec..0a6cc0edbdcc 100644 --- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php @@ -37,16 +37,19 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa private $context; private $rootNodeName = 'response'; private $loadOptions; + private $ignoredNodeTypes; /** * Construct new XmlEncoder and allow to change the root node element name. * - * @param int|null $loadOptions A bit field of LIBXML_* constants + * @param int|null $loadOptions A bit field of LIBXML_* constants + * @param int[] $ignoredNodeTypes an array of ignored XML node types, each one of the DOM Predefined XML_* Constants */ - public function __construct(string $rootNodeName = 'response', int $loadOptions = null) + public function __construct(string $rootNodeName = 'response', int $loadOptions = null, array $ignoredNodeTypes = array(XML_PI_NODE, XML_COMMENT_NODE)) { $this->rootNodeName = $rootNodeName; $this->loadOptions = null !== $loadOptions ? $loadOptions : LIBXML_NONET | LIBXML_NOBLANKS; + $this->ignoredNodeTypes = $ignoredNodeTypes; } /** @@ -105,7 +108,7 @@ public function decode($data, $format, array $context = array()) if (XML_DOCUMENT_TYPE_NODE === $child->nodeType) { throw new NotEncodableValueException('Document types are not allowed.'); } - if (!$rootNode && XML_PI_NODE !== $child->nodeType) { + if (!$rootNode && !\in_array($child->nodeType, $this->ignoredNodeTypes, true)) { $rootNode = $child; } } @@ -316,7 +319,7 @@ private function parseXmlValue(\DOMNode $node, array $context = array()) $value = array(); foreach ($node->childNodes as $subnode) { - if (XML_PI_NODE === $subnode->nodeType) { + if (\in_array($subnode->nodeType, $this->ignoredNodeTypes, true)) { continue; } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 17f7b93b4d83..39bb557c3c6c 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -515,6 +515,62 @@ public function testDecodeIgnoreWhiteSpace() $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); } + public function testDecodeIgnoreComments() + { + $source = <<<'XML' + + + + + + Benjamin + Alexandre + + + Damien + Clay + + +XML; + + $expected = array('person' => array( + array('firstname' => 'Benjamin', 'lastname' => 'Alexandre'), + array('firstname' => 'Damien', 'lastname' => 'Clay'), + )); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + + public function testDecodePreserveComments() + { + $source = <<<'XML' + + + + + Benjamin + Alexandre + + + Damien + Clay + + +XML; + + $this->encoder = new XmlEncoder('people', null, array(XML_PI_NODE)); + $serializer = new Serializer(array(new CustomNormalizer()), array('xml' => new XmlEncoder())); + $this->encoder->setSerializer($serializer); + + $expected = array('person' => array( + array('firstname' => 'Benjamin', 'lastname' => 'Alexandre', '#comment' => ' This comment should be decoded. '), + array('firstname' => 'Damien', 'lastname' => 'Clay'), + )); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + public function testDecodeAlwaysAsCollection() { $this->encoder = new XmlEncoder('response', null);