feature #23122 Xml encoder optional type cast (ragboyjr)

This PR was submitted for the 2.7 branch but it was merged into the 3.4 branch instead (closes #23122).

Discussion
----------

Xml encoder optional type cast

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #22478
| License       | MIT
| Doc PR        | n/a

This fixes the issue where certain XML attributes are typecasted when you don't want them to by providing the ability opt out of any typecasting of xml attributes via an option in the context. If this is approved, then I'll add docs in the serializer component describing the new context option.

Commits
-------

8f6e67d319 XML Encoder Optional Type Cast
This commit is contained in:
Fabien Potencier 2017-06-16 11:28:03 -07:00
commit 1cdbb7db7a
3 changed files with 48 additions and 9 deletions

View File

@ -39,6 +39,8 @@ CHANGELOG
* [DEPRECATION] the `Exception` interface has been renamed to `ExceptionInterface`
* added `ObjectNormalizer` leveraging the `PropertyAccess` component to normalize
objects containing both properties and getters / setters / issers / hassers methods.
* added `xml_type_cast_attributes` context option for allowing users to opt-out of typecasting
xml attributes.
2.6.0
-----

View File

@ -119,10 +119,10 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
unset($data['@xmlns:xml']);
if (empty($data)) {
return $this->parseXml($rootNode);
return $this->parseXml($rootNode, $context);
}
return array_merge($data, (array) $this->parseXml($rootNode));
return array_merge($data, (array) $this->parseXml($rootNode, $context));
}
if (!$rootNode->hasAttributes()) {
@ -261,11 +261,11 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
*
* @return array|string
*/
private function parseXml(\DOMNode $node)
private function parseXml(\DOMNode $node, array $context = array())
{
$data = $this->parseXmlAttributes($node);
$data = $this->parseXmlAttributes($node, $context);
$value = $this->parseXmlValue($node);
$value = $this->parseXmlValue($node, $context);
if (!count($data)) {
return $value;
@ -297,16 +297,17 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
*
* @return array
*/
private function parseXmlAttributes(\DOMNode $node)
private function parseXmlAttributes(\DOMNode $node, array $context = array())
{
if (!$node->hasAttributes()) {
return array();
}
$data = array();
$typeCastAttributes = $this->resolveXmlTypeCastAttributes($context);
foreach ($node->attributes as $attr) {
if (!is_numeric($attr->nodeValue)) {
if (!is_numeric($attr->nodeValue) || !$typeCastAttributes) {
$data['@'.$attr->nodeName] = $attr->nodeValue;
continue;
@ -331,7 +332,7 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
*
* @return array|string
*/
private function parseXmlValue(\DOMNode $node)
private function parseXmlValue(\DOMNode $node, array $context = array())
{
if (!$node->hasChildNodes()) {
return $node->nodeValue;
@ -348,7 +349,7 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
continue;
}
$val = $this->parseXml($subnode);
$val = $this->parseXml($subnode, $context);
if ('item' === $subnode->nodeName && isset($val['@key'])) {
if (isset($val['#'])) {
@ -527,6 +528,20 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
: $this->rootNodeName;
}
/**
* Get XML option for type casting attributes Defaults to true.
*
* @param array $context
*
* @return bool
*/
private function resolveXmlTypeCastAttributes(array $context = array())
{
return isset($context['xml_type_cast_attributes'])
? (bool) $context['xml_type_cast_attributes']
: true;
}
/**
* Create a DOM document, taking serializer options into account.
*

View File

@ -284,6 +284,28 @@ XML;
$this->assertSame(array('@index' => -12.11, '#' => 'Name'), $this->encoder->decode($source, 'xml'));
}
public function testNoTypeCastAttribute()
{
$source = <<<XML
<?xml version="1.0"?>
<document a="018" b="-12.11">
<node a="018" b="-12.11"/>
</document>
XML;
$data = $this->encoder->decode($source, 'xml', array('xml_type_cast_attributes' => false));
$expected = array(
'@a' => '018',
'@b' => '-12.11',
'node' => array(
'@a' => '018',
'@b' => '-12.11',
'#' => '',
),
);
$this->assertSame($expected, $data);
}
public function testEncode()
{
$source = $this->getXmlSource();