From 9d6b20caa3b80a346e2527764d9f857b8ec70c42 Mon Sep 17 00:00:00 2001 From: Matthew Vickery Date: Mon, 19 Aug 2013 19:03:30 +0200 Subject: [PATCH] Added support for encoding and decoding namespaced xml (xmlns) --- .../Serializer/Encoder/XmlEncoder.php | 25 ++++++-- .../Tests/Encoder/XmlEncoderTest.php | 63 +++++++++++++++++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php index 8c47e418a5..b51232c9f2 100644 --- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php @@ -99,7 +99,22 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec // todo: throw an exception if the root node name is not correctly configured (bc) if ($rootNode->hasChildNodes()) { - return $this->parseXml($rootNode); + + $xpath = new \DOMXPath($dom); + $data = array(); + foreach ($xpath->query('namespace::*', $dom->documentElement) as $nsNode) { + $data['@'.$nsNode->nodeName] = $nsNode->nodeValue; + } + + if (isset($data['@xmlns:xml'])) { + unset($data['@xmlns:xml']); + } + + if (empty($data)) { + return $this->parseXml($rootNode); + } + + return array_merge($data, (array) $this->parseXml($rootNode)); } if (!$rootNode->hasAttributes()) { @@ -227,7 +242,7 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec { return $name && false === strpos($name, ' ') && - preg_match('#^[\pL_][\pL0-9._-]*$#ui', $name); + preg_match('#^[\pL_][\pL0-9._:-]*$#ui', $name); } /** @@ -281,11 +296,11 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec $data = array(); - foreach ($node->attributes as $attrkey => $attr) { + foreach ($node->attributes as $attr) { if (ctype_digit($attr->nodeValue)) { - $data['@'.$attrkey] = (int) $attr->nodeValue; + $data['@'.$attr->nodeName] = (int) $attr->nodeValue; } else { - $data['@'.$attrkey] = $attr->nodeValue; + $data['@'.$attr->nodeName] = $attr->nodeValue; } } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index d3463d41bd..762427722e 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -203,6 +203,14 @@ class XmlEncoderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($source, $this->encoder->encode($obj, 'xml')); } + public function testEncodeWithNamespace() + { + $source = $this->getNamespacedXmlSource(); + $array = $this->getNamespacedArray(); + + $this->assertEquals($source, $this->encoder->encode($array, 'xml')); + } + public function testEncodeSerializerXmlRootNodeNameOption() { $options = array('xml_root_node_name' => 'test'); @@ -253,6 +261,14 @@ class XmlEncoderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $this->encoder->decode($xml, 'xml')); } + public function testDecodeWithNamespace() + { + $source = $this->getNamespacedXmlSource(); + $array = $this->getNamespacedArray(); + + $this->assertEquals($array, $this->encoder->decode($source, 'xml')); + } + public function testDecodeScalarWithAttribute() { $source = ''."\n". @@ -414,6 +430,53 @@ XML; ''."\n"; } + protected function getNamespacedXmlSource() + { + return ''."\n". + ''. + '1'. + 'foo'. + 'ab'. + 'valvalbar'. + 'title1title2'. + 'Ed'. + ''."\n"; + } + + protected function getNamespacedArray() + { + return array( + '@xmlns' => 'http://www.w3.org/2005/Atom', + '@xmlns:app' => 'http://www.w3.org/2007/app', + '@xmlns:media' => 'http://search.yahoo.com/mrss/', + '@xmlns:gd' => 'http://schemas.google.com/g/2005', + '@xmlns:yt' => 'http://gdata.youtube.com/schemas/2007', + 'qux' => "1", + 'app:foo' => "foo", + 'yt:bar' => array("a", "b"), + 'media:baz' => array( + 'media:key' => "val", + 'media:key2' => "val", + 'A B' => "bar", + 'item' => array( + array( + 'title' => 'title1', + ), + array( + 'title' => 'title2', + ) + ), + 'Barry' => array( + '@size' => 'large', + 'FooBar' => array( + 'Baz' => 'Ed', + '@gd:id' => 1, + ), + ), + ), + ); + } + protected function getObject() { $obj = new Dummy();