From 74773483143ef06b7e32642ac34c18fe3e270d79 Mon Sep 17 00:00:00 2001 From: Maximilian Ruta Date: Tue, 6 May 2025 11:12:41 +0200 Subject: [PATCH] [Serializer] Add CDATA_WRAPPING_NAME_PATTERN support to XmlEncoder --- .../Component/Serializer/Encoder/XmlEncoder.php | 13 ++++++++++--- .../Serializer/Tests/Encoder/XmlEncoderTest.php | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php index ed66fa30898df..07eb4c5ba6d62 100644 --- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php @@ -59,6 +59,7 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa public const TYPE_CAST_ATTRIBUTES = 'xml_type_cast_attributes'; public const VERSION = 'xml_version'; public const CDATA_WRAPPING = 'cdata_wrapping'; + public const CDATA_WRAPPING_NAME_PATTERN = 'cdata_wrapping_name_pattern'; public const CDATA_WRAPPING_PATTERN = 'cdata_wrapping_pattern'; public const IGNORE_EMPTY_ATTRIBUTES = 'ignore_empty_attributes'; @@ -72,6 +73,7 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa self::ROOT_NODE_NAME => 'response', self::TYPE_CAST_ATTRIBUTES => true, self::CDATA_WRAPPING => true, + self::CDATA_WRAPPING_NAME_PATTERN => false, self::CDATA_WRAPPING_PATTERN => '/[<>&]/', self::IGNORE_EMPTY_ATTRIBUTES => false, ]; @@ -440,10 +442,15 @@ private function appendNode(\DOMNode $parentNode, mixed $data, string $format, a /** * Checks if a value contains any characters which would require CDATA wrapping. + * + * @param array $context */ - private function needsCdataWrapping(string $val, array $context): bool + private function needsCdataWrapping(string $name, string $val, array $context): bool { - return ($context[self::CDATA_WRAPPING] ?? $this->defaultContext[self::CDATA_WRAPPING]) && preg_match($context[self::CDATA_WRAPPING_PATTERN] ?? $this->defaultContext[self::CDATA_WRAPPING_PATTERN], $val); + return ($context[self::CDATA_WRAPPING] ?? $this->defaultContext[self::CDATA_WRAPPING]) && + (preg_match($context[self::CDATA_WRAPPING_PATTERN] ?? $this->defaultContext[self::CDATA_WRAPPING_PATTERN], $val) || + (($context[self::CDATA_WRAPPING_NAME_PATTERN] ?? $this->defaultContext[self::CDATA_WRAPPING_NAME_PATTERN]) && preg_match($context[self::CDATA_WRAPPING_NAME_PATTERN] ?? $this->defaultContext[self::CDATA_WRAPPING_NAME_PATTERN], $name)) + ); } /** @@ -471,7 +478,7 @@ private function selectNodeType(\DOMNode $node, mixed $val, string $format, arra return $this->selectNodeType($node, $this->serializer->normalize($val, $format, $context), $format, $context); } elseif (is_numeric($val)) { return $this->appendText($node, (string) $val); - } elseif (\is_string($val) && $this->needsCdataWrapping($val, $context)) { + } elseif (\is_string($val) && $this->needsCdataWrapping($node->nodeName, $val, $context)) { return $this->appendCData($node, $val); } elseif (\is_string($val)) { return $this->appendText($node, $val); diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 78699983f7592..82d23320d7cec 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -568,6 +568,23 @@ public function testDecodeXMLWithProcessInstruction() $this->assertEquals(get_object_vars($obj), $this->encoder->decode($source, 'xml')); } + public function testCDataNamePattern() + { + $expected = <<<'XML' + + + +XML; + $source = ['person' => [ + ['firstname' => 'Benjamin', 'lastname' => 'Alexandre', 'other' => 'data'], + ['firstname' => 'Damien', 'lastname' => 'Clay', 'other' => 'data'], + ]]; + + $this->assertEquals($expected, $this->encoder->encode($source, 'xml',[ + XmlEncoder::CDATA_WRAPPING_NAME_PATTERN => '(firstname|lastname|)' + ])); + } + public function testDecodeIgnoreWhiteSpace() { $source = <<<'XML'