Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Serializer] XmlEncoder provides different types for XML attributes depending on if the XMLNode has children #51594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
themasch opened this issue Sep 7, 2023 · 0 comments

Comments

@themasch
Copy link
Contributor

themasch commented Sep 7, 2023

Symfony version(s) affected

6.3.4

Description

When deserializing XML into an object, sometimes the serializer "guesses" a field containing only digits to be an integer.
This behaviour can be controlled via the TYPE_CAST_ATTRIBUTES/xml_type_cast_attributes option.

But, this only applies if the node in question has child nodes. If its just a lone XML element without child nodes, some kind of "quick path" is taken that just copies the attribute values to an arry (as strings):

        // XmlEncoder.php line 159ff
        foreach ($rootNode->attributes as $attrKey => $attr) {
            $data['@'.$attrKey] = $attr->nodeValue;
        }

This causes different encoding results for very similar XML strings (see reproducer).

For me, setting xml_type_cast_attributes to false works around the issue, as that produces the (for us) correct behaviour in all
cases.

How to reproduce

Installed the followin libraries via composer:

        "symfony/serializer": "^6.3",
        "symfony/property-info": "^6.3",
        "symfony/property-access": "^6.3",
        "phpdocumentor/type-resolver": "^1.7",
        "phpdocumentor/reflection-docblock": "^5.3"
<?php

declare(strict_types=1);

use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Component\Serializer\Annotation\SerializedName;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;

require_once 'vendor/autoload.php';

class TestClass
{
    public function __construct(
        #[SerializedName('@aString')]
        public readonly string $aString,
        #[SerializedName('@anInt')]
        public readonly int $anInt
    ) {
    }
}

$metadataFactory = new ClassMetadataFactory(new LoaderChain([new AnnotationLoader(null)]));
$nameConverter = new MetadataAwareNameConverter($metadataFactory);
$propertyTypeExtractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]);
$classDiscriminator = new ClassDiscriminatorFromClassMetadata($metadataFactory);

$serializer = new Serializer(
    [
        new PropertyNormalizer($metadataFactory, $nameConverter, $propertyTypeExtractor, $classDiscriminator)
    ],
    [
        new XmlEncoder()
    ]
);

// this works
var_dump($serializer->deserialize('<outer aString="12345" anInt="12345"></outer>', TestClass::class, 'xml'));

// this also works
var_dump($serializer->deserialize('<outer aString="12345" anInt="12345"> </outer>', TestClass::class, 'xml', ['xml_type_cast_attributes' => false]));

// NotNormalizableValueException: The type of the "aString" attribute for class "TestClass" must be one of "string" ("int" given). 
var_dump($serializer->deserialize('<outer aString="12345" anInt="12345"> </outer>', TestClass::class, 'xml'));

Possible Solution

Handling attribute type "guessing" identical, independent from $rootNode->hasChildNodes() should result in a more consistent result. But I may be missing part of the picture here.

Additional Context

No response

@themasch themasch added the Bug label Sep 7, 2023
nicolas-grekas added a commit that referenced this issue Sep 29, 2023
This PR was merged into the 5.4 branch.

Discussion
----------

[Serializer] Fix parsing XML root node attributes

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #51594
| License       | MIT
| Doc PR        | N/A

Add missing parsing of root node attributes

Commits
-------

4dc3cef [Serializer] Fix parsing XML root node attributes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants