diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
index 671ab97852ff1..0bd85b0247961 100644
--- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
+++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
@@ -369,7 +369,10 @@ private function buildXml(\DOMNode $parentNode, $data, $xmlRootNodeName = null)
if (is_array($data) || ($data instanceof \Traversable && !$this->serializer->supportsNormalization($data, $this->format))) {
foreach ($data as $key => $data) {
//Ah this is the magic @ attribute types.
- if (0 === strpos($key, '@') && is_scalar($data) && $this->isElementNameValid($attributeName = substr($key, 1))) {
+ if (0 === strpos($key, '@') && $this->isElementNameValid($attributeName = substr($key, 1))) {
+ if (!is_scalar($data)) {
+ $data = $this->serializer->normalize($data, $this->format, $this->context);
+ }
$parentNode->setAttribute($attributeName, $data);
} elseif ($key === '#') {
$append = $this->selectNodeType($parentNode, $data);
@@ -474,7 +477,7 @@ private function selectNodeType(\DOMNode $node, $val)
} elseif ($val instanceof \Traversable) {
$this->buildXml($node, $val);
} elseif (is_object($val)) {
- return $this->buildXml($node, $this->serializer->normalize($val, $this->format, $this->context));
+ return $this->selectNodeType($node, $this->serializer->normalize($val, $this->format, $this->context));
} elseif (is_numeric($val)) {
return $this->appendText($node, (string) $val);
} elseif (is_string($val) && $this->needsCdataWrapping($val)) {
diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
index 1c9ed79e35d62..e455e2d224e8c 100644
--- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
@@ -19,11 +19,17 @@
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class XmlEncoderTest extends TestCase
{
+ /**
+ * @var XmlEncoder
+ */
private $encoder;
+ private $exampleDateTimeString = '2017-02-19T15:16:08+0300';
+
protected function setUp()
{
$this->encoder = new XmlEncoder();
@@ -524,4 +530,89 @@ protected function getObject()
return $obj;
}
+
+ public function testEncodeXmlWithBoolValue()
+ {
+ $expectedXml = <<<'XML'
+
+10
+
+XML;
+
+ $actualXml = $this->encoder->encode(array('foo' => true, 'bar' => false), 'xml');
+
+ $this->assertEquals($expectedXml, $actualXml);
+ }
+
+ public function testEncodeXmlWithDateTimeObjectValue()
+ {
+ $xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer();
+
+ $actualXml = $xmlEncoder->encode(array('dateTime' => new \DateTime($this->exampleDateTimeString)), 'xml');
+
+ $this->assertEquals($this->createXmlWithDateTime(), $actualXml);
+ }
+
+ public function testEncodeXmlWithDateTimeObjectField()
+ {
+ $xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer();
+
+ $actualXml = $xmlEncoder->encode(array('foo' => array('@dateTime' => new \DateTime($this->exampleDateTimeString))), 'xml');
+
+ $this->assertEquals($this->createXmlWithDateTimeField(), $actualXml);
+ }
+
+ /**
+ * @return XmlEncoder
+ */
+ private function createXmlEncoderWithDateTimeNormalizer()
+ {
+ $encoder = new XmlEncoder();
+ $serializer = new Serializer(array($this->createMockDateTimeNormalizer()), array('xml' => new XmlEncoder()));
+ $encoder->setSerializer($serializer);
+
+ return $encoder;
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|NormalizerInterface
+ */
+ private function createMockDateTimeNormalizer()
+ {
+ $mock = $this->getMockBuilder('\Symfony\Component\Serializer\Normalizer\CustomNormalizer')->getMock();
+
+ $mock
+ ->expects($this->once())
+ ->method('normalize')
+ ->with(new \DateTime($this->exampleDateTimeString), 'xml', array())
+ ->willReturn($this->exampleDateTimeString);
+
+ $mock
+ ->expects($this->once())
+ ->method('supportsNormalization')
+ ->with(new \DateTime($this->exampleDateTimeString), 'xml')
+ ->willReturn(true);
+
+ return $mock;
+ }
+
+ /**
+ * @return string
+ */
+ private function createXmlWithDateTime()
+ {
+ return sprintf('
+%s
+', $this->exampleDateTimeString);
+ }
+
+ /**
+ * @return string
+ */
+ private function createXmlWithDateTimeField()
+ {
+ return sprintf('
+
+', $this->exampleDateTimeString);
+ }
}