Skip to content

Commit

Permalink
[Serializer] Add XmlEncoder::CDATA_WRAPPING_PATTERN context option
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpozzi committed Apr 30, 2024
1 parent f738888 commit 8ab57d1
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Component/Serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ CHANGELOG
* Add `AbstractNormalizer::FILTER_BOOL` context option
* Add `CamelCaseToSnakeCaseNameConverter::REQUIRE_SNAKE_CASE_PROPERTIES` context option
* Deprecate `AbstractNormalizerContextBuilder::withDefaultContructorArguments(?array $defaultContructorArguments)`, use `withDefaultConstructorArguments(?array $defaultConstructorArguments)` instead (note the missing `s` character in Contructor word in deprecated method)
* Add `XmlEncoder::CDATA_WRAPPING_PATTERN` context option

7.0
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,12 @@ public function withCdataWrapping(?bool $cdataWrapping): static
{
return $this->with(XmlEncoder::CDATA_WRAPPING, $cdataWrapping);
}

/**
* Configures the pattern used to evaluate if a CDATA section should be added.
*/
public function withCdataWrappingPattern(?string $cdataWrappingPattern): static
{
return $this->with(XmlEncoder::CDATA_WRAPPING_PATTERN, $cdataWrappingPattern);
}
}
4 changes: 3 additions & 1 deletion src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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_PATTERN = 'cdata_wrapping_pattern';

private array $defaultContext = [
self::AS_COLLECTION => false,
Expand All @@ -70,6 +71,7 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa
self::ROOT_NODE_NAME => 'response',
self::TYPE_CAST_ATTRIBUTES => true,
self::CDATA_WRAPPING => true,
self::CDATA_WRAPPING_PATTERN => '/[<>&]/',
];

public function __construct(array $defaultContext = [])
Expand Down Expand Up @@ -433,7 +435,7 @@ private function appendNode(\DOMNode $parentNode, mixed $data, string $format, a
*/
private function needsCdataWrapping(string $val, array $context): bool
{
return ($context[self::CDATA_WRAPPING] ?? $this->defaultContext[self::CDATA_WRAPPING]) && preg_match('/[<>&]/', $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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function testWithers(array $values)
->withTypeCastAttributes($values[XmlEncoder::TYPE_CAST_ATTRIBUTES])
->withVersion($values[XmlEncoder::VERSION])
->withCdataWrapping($values[XmlEncoder::CDATA_WRAPPING])
->withCdataWrappingPattern($values[XmlEncoder::CDATA_WRAPPING_PATTERN])
->toArray();

$this->assertSame($values, $context);
Expand All @@ -67,6 +68,7 @@ public static function withersDataProvider(): iterable
XmlEncoder::TYPE_CAST_ATTRIBUTES => true,
XmlEncoder::VERSION => '1.0',
XmlEncoder::CDATA_WRAPPING => false,
XmlEncoder::CDATA_WRAPPING_PATTERN => '/[<>&"\']/',
]];

yield 'With null values' => [[
Expand All @@ -83,6 +85,7 @@ public static function withersDataProvider(): iterable
XmlEncoder::TYPE_CAST_ATTRIBUTES => null,
XmlEncoder::VERSION => null,
XmlEncoder::CDATA_WRAPPING => null,
XmlEncoder::CDATA_WRAPPING_PATTERN => null,
]];
}
}
52 changes: 46 additions & 6 deletions src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,16 +231,56 @@ public function testEncodeRootAttributes()
$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
}

public function testEncodeCdataWrapping()
/**
* @dataProvider encodeCdataWrappingWithDefaultPattern
*/
public function testEncodeCdataWrappingWithDefaultPattern($input, $expected)
{
$array = [
'firstname' => 'Paul & Martha <or Me>',
$this->assertEquals($expected, $this->encoder->encode($input, 'xml'));
}

public static function encodeCdataWrappingWithDefaultPattern()
{
return [
[
['firstname' => 'Paul and Martha'],
'<?xml version="1.0"?>'."\n".'<response><firstname>Paul and Martha</firstname></response>'."\n",
],
[
['lastname' => 'O\'Donnel'],
'<?xml version="1.0"?>'."\n".'<response><lastname>O\'Donnel</lastname></response>'."\n",
],
[
['firstname' => 'Paul & Martha <or Me>'],
'<?xml version="1.0"?>'."\n".'<response><firstname><![CDATA[Paul & Martha <or Me>]]></firstname></response>'."\n",
],
];
}

$expected = '<?xml version="1.0"?>'."\n".
'<response><firstname><![CDATA[Paul & Martha <or Me>]]></firstname></response>'."\n";
/**
* @dataProvider encodeCdataWrappingWithCustomPattern
*/
public function testEncodeCdataWrappingWithCustomPattern($input, $expected)
{
$this->assertEquals($expected, $this->encoder->encode($input, 'xml', ['cdata_wrapping_pattern' => '/[<>&"\']/']));
}

$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
public static function encodeCdataWrappingWithCustomPattern()
{
return [
[
['firstname' => 'Paul and Martha'],
'<?xml version="1.0"?>'."\n".'<response><firstname>Paul and Martha</firstname></response>'."\n",
],
[
['lastname' => 'O\'Donnel'],
'<?xml version="1.0"?>'."\n".'<response><lastname><![CDATA[O\'Donnel]]></lastname></response>'."\n",
],
[
['firstname' => 'Paul & Martha <or Me>'],
'<?xml version="1.0"?>'."\n".'<response><firstname><![CDATA[Paul & Martha <or Me>]]></firstname></response>'."\n",
],
];
}

public function testEnableCdataWrapping()
Expand Down

0 comments on commit 8ab57d1

Please sign in to comment.