 .../src/Functional/CookieResourceTestTrait.php     |   2 +-
 .../EntityResource/Action/ActionXmlAnonTest.php    |  26 ++++
 .../Action/ActionXmlBasicAuthTest.php              |  36 +++++
 .../EntityResource/Action/ActionXmlCookieTest.php  |  31 ++++
 .../EntityResource/Comment/CommentXmlAnonTest.php  |  63 +++++++++
 .../Comment/CommentXmlBasicAuthTest.php            |  52 +++++++
 .../Comment/CommentXmlCookieTest.php               |  47 +++++++
 .../EntityResource/EntityResourceTestBase.php      |  76 ++++++++--
 .../EntityResource/Feed/FeedXmlAnonTest.php        |  26 ++++
 .../EntityResource/Feed/FeedXmlBasicAuthTest.php   |  40 ++++++
 .../EntityResource/Feed/FeedXmlCookieTest.php      |  31 ++++
 .../EntityResource/Item/ItemXmlAnonTest.php        |  26 ++++
 .../EntityResource/Item/ItemXmlBasicAuthTest.php   |  36 +++++
 .../EntityResource/Item/ItemXmlCookieTest.php      |  31 ++++
 .../MenuLinkContent/MenuLinkContentXmlAnonTest.php |  26 ++++
 .../MenuLinkContentXmlBasicAuthTest.php            |  36 +++++
 .../MenuLinkContentXmlCookieTest.php               |  31 ++++
 .../EntityResource/Node/NodeXmlAnonTest.php        |  26 ++++
 .../EntityResource/Node/NodeXmlBasicAuthTest.php   |  36 +++++
 .../EntityResource/Node/NodeXmlCookieTest.php      |  31 ++++
 .../Shortcut/ShortcutXmlAnonTest.php               |  26 ++++
 .../Shortcut/ShortcutXmlBasicAuthTest.php          |  36 +++++
 .../Shortcut/ShortcutXmlCookieTest.php             |  31 ++++
 .../EntityResource/Term/TermXmlAnonTest.php        |  26 ++++
 .../EntityResource/Term/TermXmlBasicAuthTest.php   |  36 +++++
 .../EntityResource/Term/TermXmlCookieTest.php      |  31 ++++
 .../EntityResource/User/UserXmlAnonTest.php        |  35 +++++
 .../EntityResource/User/UserXmlBasicAuthTest.php   |  46 ++++++
 .../EntityResource/User/UserXmlCookieTest.php      |  39 ++++++
 .../XmlEntityNormalizationQuirksTrait.php          | 156 +++++++++++++++++++++
 .../src/Functional/XmlNormalizationQuirksTrait.php |  36 +++++
 31 files changed, 1197 insertions(+), 10 deletions(-)

diff --git a/core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php b/core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php
index 8975c3f..689fa83 100644
--- a/core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php
+++ b/core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php
@@ -61,7 +61,7 @@ protected function initAuthentication() {
       'pass' => $this->account->passRaw,
     ];
 
-    $request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, 'json');
+    $request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, static::$format);
     $request_options[RequestOptions::HEADERS] = [
       'Content-Type' => static::$mimeType,
     ];
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlAnonTest.php
new file mode 100644
index 0000000..3bce75e
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Action;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ActionXmlAnonTest extends ActionResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlBasicAuthTest.php
new file mode 100644
index 0000000..a81051d
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlBasicAuthTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Action;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ActionXmlBasicAuthTest extends ActionResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlCookieTest.php
new file mode 100644
index 0000000..85b28ac
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Action/ActionXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Action;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ActionXmlCookieTest extends ActionResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlAnonTest.php
new file mode 100644
index 0000000..aa45f5c
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlAnonTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class CommentXmlAnonTest extends CommentResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   *
+   * Anononymous users cannot edit their own comments.
+   *
+   * @see \Drupal\comment\CommentAccessControlHandler::checkAccess
+   *
+   * Therefore we grant them the 'administer comments' permission for the
+   * purpose of this test.
+   *
+   * @see ::setUpAuthorization
+   */
+  protected static $patchProtectedFieldNames = [
+    'pid',
+    'entity_id',
+    'changed',
+    'thread',
+    'entity_type',
+    'field_name',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPostDxWithoutCriticalBaseFields() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPostSkipCommentApproval() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlBasicAuthTest.php
new file mode 100644
index 0000000..c167ea7
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlBasicAuthTest.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class CommentXmlBasicAuthTest extends CommentResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPostDxWithoutCriticalBaseFields() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPostSkipCommentApproval() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlCookieTest.php
new file mode 100644
index 0000000..1ece71b
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentXmlCookieTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class CommentXmlCookieTest extends CommentResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPostDxWithoutCriticalBaseFields() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPostSkipCommentApproval() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
index 72589bd..eac468f 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -180,11 +180,29 @@ public function setUp() {
         ->setTranslatable(FALSE)
         ->save();
 
-      // Reload entity so that it has the new field.
+      // Add multi-value field.
+      FieldStorageConfig::create([
+        'entity_type' => static::$entityTypeId,
+        'field_name' => 'field_rest_test_multivalue',
+        'type' => 'string',
+      ])
+        ->setCardinality(2)
+        ->save();
+      FieldConfig::create([
+        'entity_type' => static::$entityTypeId,
+        'field_name' => 'field_rest_test_multivalue',
+        'bundle' => $this->entity->bundle(),
+      ])
+        ->setLabel('Test field: multi-value')
+        ->setTranslatable(FALSE)
+        ->save();
+
+      // Reload entity so that it has the new fields.
       $this->entity = $this->entityStorage->loadUnchanged($this->entity->id());
 
-      // Set a default value on the field.
+      // Set a default value on the fields.
       $this->entity->set('field_rest_test', ['value' => 'All the faith he had had had had no effect on the outcome of his life.']);
+      $this->entity->set('field_rest_test_multivalue', [['value' => 'One'], ['value' => 'Two']]);
       $this->entity->save();
     }
   }
@@ -460,6 +478,18 @@ public function testGet() {
     // for the keys with the array order the same (it needs to match with
     // identical comparison).
     $expected = $this->getExpectedNormalizedEntity();
+    if ($this->entity instanceof FieldableEntityInterface) {
+      $expected += [
+        'field_rest_test_multivalue' => [
+          0 => [
+            'value' => 'One',
+          ],
+          1 => [
+            'value' => 'Two',
+          ],
+        ]
+      ];
+    }
     static::recursiveKSort($expected);
     $actual = $this->serializer->decode((string) $response->getBody(), static::$format);
     static::recursiveKSort($actual);
@@ -467,8 +497,12 @@ public function testGet() {
 
     // Not only assert the normalization, also assert deserialization of the
     // response results in the expected object.
-    $unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
-    $this->assertSame($unserialized->uuid(), $this->entity->uuid());
+    // Note: deserialization of the XML format is not supported, so only test
+    // this for other formats.
+    if (static::$format !== 'xml') {
+      $unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
+      $this->assertSame($unserialized->uuid(), $this->entity->uuid());
+    }
     // Finally, assert that the expected 'Link' headers are present.
     if ($this->entity->getEntityType()->getLinkTemplates()) {
       $this->assertArrayHasKey('Link', $response->getHeaders());
@@ -491,11 +525,11 @@ public function testGet() {
     $get_headers = $response->getHeaders();
 
     // Verify that the GET and HEAD responses are the same. The only difference
-    // is that there's no body. For this reason the 'Transfer-Encoding' header
-    // is also added to the list of headers to ignore, as this could be added to
-    // GET requests - depending on web server configuration. This would usually
-    // be 'Transfer-Encoding: chunked'.
-    $ignored_headers = ['Date', 'Content-Length', 'X-Drupal-Cache', 'X-Drupal-Dynamic-Cache', 'Transfer-Encoding'];
+    // is that there's no body. For this reason the 'Transfer-Encoding' and
+    // 'Vary' headers are also added to the list of headers to ignore, as they
+    // may be to GET requests - depending on web server configuration. They are
+    // usually 'Transfer-Encoding: chunked' and 'Vary: Accept-Encoding'.
+    $ignored_headers = ['Date', 'Content-Length', 'X-Drupal-Cache', 'X-Drupal-Dynamic-Cache', 'Transfer-Encoding', 'Vary'];
     foreach ($ignored_headers as $ignored_header) {
       unset($head_headers[$ignored_header]);
       unset($get_headers[$ignored_header]);
@@ -522,6 +556,18 @@ public function testGet() {
       // normalized entity's values to strings. This ensures the BC layer for
       // bc_primitives_as_strings works as expected.
       $expected = $this->getExpectedNormalizedEntity();
+      if ($this->entity instanceof FieldableEntityInterface) {
+        $expected += [
+          'field_rest_test_multivalue' => [
+            0 => [
+              'value' => 'One',
+            ],
+            1 => [
+              'value' => 'Two',
+            ],
+          ]
+        ];
+      }
       // Config entities are not affected.
       // @see \Drupal\serialization\Normalizer\ConfigEntityNormalizer::normalize()
       $expected = static::castToString($expected);
@@ -557,6 +603,18 @@ public function testGet() {
       // ::formatExpectedTimestampValue() to generate the timestamp value. This
       // will take into account the above config setting.
       $expected = $this->getExpectedNormalizedEntity();
+      if ($this->entity instanceof FieldableEntityInterface) {
+        $expected += [
+          'field_rest_test_multivalue' => [
+            0 => [
+              'value' => 'One',
+            ],
+            1 => [
+              'value' => 'Two',
+            ],
+          ]
+        ];
+      }
       // Config entities are not affected.
       // @see \Drupal\serialization\Normalizer\ConfigEntityNormalizer::normalize()
       static::recursiveKSort($expected);
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlAnonTest.php
new file mode 100644
index 0000000..f2a3233
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class FeedXmlAnonTest extends FeedResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlBasicAuthTest.php
new file mode 100644
index 0000000..3a8b69e
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlBasicAuthTest.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class FeedXmlBasicAuthTest extends FeedResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+  public function testGet() {
+    return parent::testGet(); // TODO: Change the autogenerated stub
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlCookieTest.php
new file mode 100644
index 0000000..377690a
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Feed/FeedXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class FeedXmlCookieTest extends FeedResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlAnonTest.php
new file mode 100644
index 0000000..72a3035
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Item;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ItemXmlAnonTest extends ItemResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlBasicAuthTest.php
new file mode 100644
index 0000000..8da0a58
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlBasicAuthTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Item;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ItemXmlBasicAuthTest extends ItemResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlCookieTest.php
new file mode 100644
index 0000000..5fae069
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Item/ItemXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Item;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ItemXmlCookieTest extends ItemResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlAnonTest.php
new file mode 100644
index 0000000..5141cb7
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class MenuLinkContentXmlAnonTest extends MenuLinkContentResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlBasicAuthTest.php
new file mode 100644
index 0000000..6a62f36
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlBasicAuthTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class MenuLinkContentXmlBasicAuthTest extends MenuLinkContentResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlCookieTest.php
new file mode 100644
index 0000000..f73d493
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/MenuLinkContent/MenuLinkContentXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class MenuLinkContentXmlCookieTest extends MenuLinkContentResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlAnonTest.php
new file mode 100644
index 0000000..eb06390
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Node;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class NodeXmlAnonTest extends NodeResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlBasicAuthTest.php
new file mode 100644
index 0000000..93838f2
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlBasicAuthTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Node;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class NodeXmlBasicAuthTest extends NodeResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlCookieTest.php
new file mode 100644
index 0000000..39ae7dd
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Node;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class NodeXmlCookieTest extends NodeResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlAnonTest.php
new file mode 100644
index 0000000..5929d32
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ShortcutXmlAnonTest extends ShortcutResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlBasicAuthTest.php
new file mode 100644
index 0000000..161ecf2
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlBasicAuthTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ShortcutXmlBasicAuthTest extends ShortcutResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlCookieTest.php
new file mode 100644
index 0000000..7623e29
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class ShortcutXmlCookieTest extends ShortcutResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlAnonTest.php
new file mode 100644
index 0000000..4f0a533
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlAnonTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Term;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class TermXmlAnonTest extends TermResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlBasicAuthTest.php
new file mode 100644
index 0000000..c890316
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlBasicAuthTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Term;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class TermXmlBasicAuthTest extends TermResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlCookieTest.php
new file mode 100644
index 0000000..4d51abb
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermXmlCookieTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Term;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class TermXmlCookieTest extends TermResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlAnonTest.php
new file mode 100644
index 0000000..ce8d7f8
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlAnonTest.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\User;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\User\UserResourceTestBase;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class UserXmlAnonTest extends UserResourceTestBase {
+
+  use AnonResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPatchDxForSecuritySensitiveBaseFields() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlBasicAuthTest.php
new file mode 100644
index 0000000..9a73bf6
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlBasicAuthTest.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\User;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\User\UserResourceTestBase;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+use Drupal\user\Entity\User;
+
+/**
+ * @group rest
+ */
+class UserXmlBasicAuthTest extends UserResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPatchDxForSecuritySensitiveBaseFields() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlCookieTest.php
new file mode 100644
index 0000000..d1ef16e
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/User/UserXmlCookieTest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\User;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
+
+/**
+ * @group rest
+ */
+class UserXmlCookieTest extends UserResourceTestBase {
+
+  use CookieResourceTestTrait;
+  use XmlEntityNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'xml';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'text/xml; charset=UTF-8';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPatchDxForSecuritySensitiveBaseFields() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
new file mode 100644
index 0000000..ca9ff74
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Field\Plugin\Field\FieldType\BooleanItem;
+use Drupal\Core\Field\Plugin\Field\FieldType\ChangedItem;
+use Drupal\Core\Field\Plugin\Field\FieldType\CreatedItem;
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
+use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem;
+use Drupal\options\Plugin\Field\FieldType\ListIntegerItem;
+use Drupal\path\Plugin\Field\FieldType\PathItem;
+use Drupal\Tests\rest\Functional\XmlNormalizationQuirksTrait;
+
+/**
+ * Trait for EntityResourceTestBase subclasses testing $format='xml'.
+ */
+trait XmlEntityNormalizationQuirksTrait {
+
+  use XmlNormalizationQuirksTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getExpectedNormalizedEntity() {
+    $default_normalization = parent::getExpectedNormalizedEntity();
+
+    if ($this->entity instanceof FieldableEntityInterface) {
+      $normalization = $this->applyXmlFieldDecodingQuirks($default_normalization);
+    }
+    else {
+      $normalization = $this->applyXmlConfigEntityDecodingQuirks($default_normalization);
+    }
+    $normalization = $this->applyXmlDecodingQuirks($normalization);
+
+    return $normalization;
+  }
+
+  /**
+   * Applies the XML entity field encoding quirks that remain after decoding.
+   *
+   * The XML encoding:
+   * - loses type data (int and bool become string)
+   *
+   * @param array $normalization
+   *   An entity normalization.
+   *
+   * @return array
+   *   The updated fieldable entity normalization.
+   *
+   * @see \Symfony\Component\Serializer\Encoder\XmlEncoder
+   */
+  protected function applyXmlFieldDecodingQuirks(array $normalization) {
+    if (!$this->entity instanceof FieldableEntityInterface) {
+      throw new \LogicException('This trait should only be used for fieldable entity types.');
+    }
+
+    foreach ($this->entity->getFields(TRUE) as $field_name => $field) {
+      // Not every field is accessible.
+      if (!isset($normalization[$field_name])) {
+        continue;
+      }
+
+      for ($i = 0; $i < count($normalization[$field_name]); $i++) {
+        switch ($field->getItemDefinition()->getClass()) {
+          case BooleanItem::class:
+            $value = &$normalization[$field_name][$i]['value'];
+            $value = $value === TRUE ? '1' : '0';
+            break;
+          case IntegerItem::class:
+          case ListIntegerItem::class:
+            $value = &$normalization[$field_name][$i]['value'];
+            $value = (string) $value;
+            break;
+          case PathItem::class:
+            $pid = &$normalization[$field_name][$i]['pid'];
+            $pid = (string) $pid;
+            break;
+          case EntityReferenceItem::class:
+            $target_id = &$normalization[$field_name][$i]['target_id'];
+            $target_id = (string) $target_id;
+            break;
+          case ChangedItem::class:
+          case CreatedItem::class:
+          case TimestampItem::class:
+            $value = &$normalization[$field_name][$i]['value'];
+            if (is_numeric($value)) {
+              $value = (string) $value;
+            }
+
+            break;
+        }
+      }
+
+      if (!empty($normalization[$field_name])) {
+        $normalization[$field_name] = $normalization[$field_name][0];
+      }
+    }
+
+    return $normalization;
+  }
+
+
+  /**
+   * Applies the XML config entity encoding quirks that remain after decoding.
+   *
+   * The XML encoding:
+   * - loses type data (int and bool become string)
+   * - converts single-item arrays into single items (non-arrays)
+   *
+   * @param array $normalization
+   *   An entity normalization.
+   *
+   * @return array
+   *   The updated config entity normalization.
+   *
+   * @see \Symfony\Component\Serializer\Encoder\XmlEncoder
+   */
+  protected function applyXmlConfigEntityDecodingQuirks(array $normalization) {
+    if (!$this->entity instanceof ConfigEntityInterface) {
+      throw new \LogicException('This trait should only be used for config entity types.');
+    }
+
+    $normalization = static::castToString($normalization);
+
+    // When a single dependency is listed, it's not decoded into an array.
+    if (isset($normalization['dependencies'])) {
+      foreach ($normalization['dependencies'] as $dependency_type => $dependency_list) {
+        if (count($dependency_list) === 1) {
+          $normalization['dependencies'][$dependency_type] = $dependency_list[0];
+        }
+      }
+    }
+
+    return $normalization;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPost() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testPatch() {
+    // Deserialization of the XML format is not supported.
+    $this->markTestSkipped();
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/XmlNormalizationQuirksTrait.php b/core/modules/rest/tests/src/Functional/XmlNormalizationQuirksTrait.php
new file mode 100644
index 0000000..4c7c455
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/XmlNormalizationQuirksTrait.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional;
+
+/**
+ * Trait for ResourceTestBase subclasses testing $format='xml'.
+ */
+trait XmlNormalizationQuirksTrait {
+
+  /**
+   * Applies the XML encoding quirks that remain after decoding.
+   *
+   * The XML encoding:
+   * - maps empty arrays to the empty string
+   *
+   * @param array $normalization
+   *   A normalization.
+   *
+   * @return array
+   *   The updated normalization.
+   *
+   * @see \Symfony\Component\Serializer\Encoder\XmlEncoder
+   */
+  protected function applyXmlDecodingQuirks(array $normalization) {
+    foreach ($normalization as $key => $value) {
+      if ($value === [] || $value === NULL) {
+        $normalization[$key] = '';
+      }
+      elseif (is_array($value)) {
+        $normalization[$key] = $this->applyXmlDecodingQuirks($value);
+      }
+    }
+    return $normalization;
+  }
+
+}
