Skip to content

Legacy TODO in XmlEncoder regarding root node name during decoding #61441 #61466

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

Open
wants to merge 5 commits into
base: 7.4
Choose a base branch
from

Conversation

mudassaralichouhan
Copy link

@mudassaralichouhan mudassaralichouhan commented Aug 20, 2025

Q A
Branch? 7.4
Bug fix? no
New feature? yes
Deprecations? yes
Issues #61441
License MIT

Add root node validation to XmlEncoder::decode() when configured via context options.


What it does and why

This PR implements a long-standing TODO in XmlEncoder::decode() related to root node validation during decoding.

  • New context options

    • validate_root_node_exists (default: false)
      • When true: decoding throws if the XML has no valid root node.
      • When false: decoding continues, but triggers a deprecation warning in 7.4 (will throw by default in 8.0).
    • validate_root_node_name (default: false)
      • When true: decoding throws if the root node name does not match the expected root_node_name.
      • When false: decoding continues, but triggers a deprecation warning in 7.4 (will throw by default in 8.0).
  • Deprecations

    • Triggered in 7.4 when decoding without validation.
    • Users are guided to set the new context flags to opt-in explicitly.
    • In Symfony 8.0, validation will be strict by default.
  • Benefits

    • Prevents fatal errors when XML contains no valid root node.
    • Aligns decoding behavior with encoding semantics.
    • Provides a clear migration path (warnings in 7.4, exceptions in 8.0).

Example

$xml = '<?xml version="1.0"?><wrongRoot><item>value</item></wrongRoot>';

$decoder = new XmlEncoder();

// Explicit validation
$decoder->decode($xml, 'xml', [
    'root_node_name' => 'expectedRoot',
    'validate_root_node_name' => true,
]);
// Throws NotEncodableValueException: Expected root node "expectedRoot", but found "wrongRoot".

// With default options (7.4)
$decoder->decode($xml, 'xml', ['root_node_name' => 'expectedRoot']);
// Decodes, but triggers a deprecation warning (will throw in 8.0).

…name is provided; add tests for mismatch and missing root cases
@carsonbot carsonbot added this to the 7.4 milestone Aug 20, 2025
@carsonbot carsonbot changed the title Serializer XmlEncoder: validate decoded root node when xml_root_node_… Serializer XmlEncoder: validate decoded root node when xml_root_node_… Aug 20, 2025
@mudassaralichouhan
Copy link
Author

Why we did this

  • Close a long-standing TODO: The encoder already supports configuring a root node name, but decoding didn’t validate this — leaving an inconsistency.
  • Improve safety and semantic symmetry: If a caller expects a specific root node, decoding a different one without error is risky. This PR introduces optional validation during decoding to mirror the expectations set during encoding.

Why this decision

  • Preserves backward compatibility: Validation is only enforced when xml_root_node_name is explicitly passed in the decode context. We use array_key_exists() to avoid applying the default "response" unintentionally.

  • Predictable error handling: The class already throws NotEncodableValueException for XML errors (e.g. empty payloads, disallowed document types). We extend that pattern for:

    • Root node mismatch
    • Missing root node

What we understood

  • Correct option key usage: The relevant key is xml_root_node_name, via the class constant XmlEncoder::ROOT_NODE_NAME, not a generic or undocumented string.
  • How DOM parsing behaves: XML documents may contain comments, whitespace, or processing instructions. These are ignored, so a document might appear valid but have no actual root element. We now guard against this.

Why this is the best fit

  • Zero-cost unless opted in: The change has no effect unless xml_root_node_name is explicitly set — preserving existing behavior.
  • Minimal, targeted logic: Adds a simple conditional check, no API changes, no broader refactors.
  • Improved error safety: Prevents null dereferences and avoids silently accepting structurally invalid or incorrect XML.

Added

  • A guard clause to throw a clear error when no root node is present.

  • An optional root name match check. If the expected and actual root nodes differ:

    throw new NotEncodableValueException(sprintf('Expected root node "%s", but found "%s".', $expected, $actual));

@mudassaralichouhan mudassaralichouhan changed the title Serializer XmlEncoder: validate decoded root node when xml_root_node_… [Serializer] Legacy TODO in XmlEncoder regarding root node name during decoding #61441 Aug 20, 2025
Co-authored-by: Oskar Stark <oskarstark@googlemail.com>
@carsonbot carsonbot changed the title [Serializer] Legacy TODO in XmlEncoder regarding root node name during decoding #61441 Legacy TODO in XmlEncoder regarding root node name during decoding #61441 Aug 23, 2025
Co-authored-by: Fabien Potencier <fabien@potencier.org>
throw new NotEncodableValueException(\sprintf('Expected root node "%s", but found "%s".', $expectedRootName, $rootNode->nodeName));
}

trigger_deprecation('symfony/serializer', '7.4', 'Decoding XML with a mismatching root node name is deprecated and will throw an exception in 8.0. Expected root node "%s", but found "%s". Set the "%s" context option to true to enable validation now.', $expectedRootName, $rootNode->nodeName, self::VALIDATE_ROOT_NODE_NAME);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not done already we need to require Symfony/deprecation-contracts

@OskarStark
Copy link
Contributor

PR body needs an update after the change of the option name

…false); deprecate throwing on missing root node; return empty array for BC when validation disabled; update tests to use correct constants
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants