Description
Related: #32114
Description
Currently, using JSON is the facto standard and well supported for all normalizers.
What I found is that the XmlEncoder
decodes/encodes the XML to array, but converts extra attributes with a @
prefix and uses #
to identity the node value.
This conversion makes it extremely difficult to use the ObjectNormalizer
and fill out DTOs with specific XML data instead of consuming just the array returned by the XmlEncoder
.
Example:
The array:
['foo' => ['@bar' => 'value', '#' => 'baz']];
generates the following XML output:
<?xml version="1.0"?>
<response>
<foo bar="value">
baz
</foo>
</response>
What if I want to use my own DTOs?
Possible solution
Create a custom name converter that handles the extra attributes and XML node values. That way you can out of the box, use the ObjectNormalizer
to set specific attributes in a specific object.
Example
We can use custom prefixes for attributes and node values, so we match them with our DTOs:
final class SpecialAttributesConverter implements NameConverterInterface
{
const ATTRIBUTE_PREFIX = 'attr';
const NODE_VALUE_ATTRIBUTE_NAME = 'value';
/**
* {@inheritdoc}
*/
public function normalize($propertyName): string
{
if (self::NODE_VALUE_ATTRIBUTE_NAME === substr($propertyName, 0, strlen(self::NODE_VALUE_ATTRIBUTE_NAME))) {
return '#';
}
if (self::ATTRIBUTE_PREFIX === substr($propertyName, 0, strlen(self::ATTRIBUTE_PREFIX))) {
return '@' . substr($propertyName, strlen(self::ATTRIBUTE_PREFIX));
}
return $propertyName;
}
/**
* {@inheritdoc}
*/
public function denormalize($propertyName): string
{
if (0 === strpos($propertyName, '#')) {
return self::NODE_VALUE_ATTRIBUTE_NAME;
}
if (0 === strpos($propertyName, '@')) {
return self::ATTRIBUTE_PREFIX . substr($propertyName, 1);
}
return $propertyName;
}
}
By using this name converter, we can configure the ObjectNormalizer
:
$objectNormalizer = new ObjectNormalizer(null, new SpecialAttributesConverter(), null, $phpDocExtractor);
and pass it to the serializer.
If we had this name converter already in the serializer package, we could create documentation that supported the integration between the XmlEncoder
and the ObjectNormalizer
like JSON
is already supported.
Would be great to get your feedback and if needed, I could create all the documentation and PR needed and improve current implementation (like passing the attribute/node value naming to the name converter constructor for example).