Bläddra i källkod

Add support for XML namespace on the XML root element

Andreas Ferber 11 år sedan
förälder
incheckning
878579ada9

+ 5 - 0
src/JMS/Serializer/Annotation/XmlRoot.php

@@ -29,4 +29,9 @@ final class XmlRoot
      * @var string
      */
     public $name;
+
+    /**
+     * @var string
+     */
+    public $namespace;
 }

+ 4 - 0
src/JMS/Serializer/Metadata/ClassMetadata.php

@@ -45,6 +45,7 @@ class ClassMetadata extends MergeableClassMetadata
     public $postDeserializeMethods = array();
 
     public $xmlRootName;
+    public $xmlRootNamespace;
     public $xmlNamespaces = array();
     public $accessorOrder;
     public $customOrder;
@@ -139,6 +140,7 @@ class ClassMetadata extends MergeableClassMetadata
         $this->postSerializeMethods = array_merge($this->postSerializeMethods, $object->postSerializeMethods);
         $this->postDeserializeMethods = array_merge($this->postDeserializeMethods, $object->postDeserializeMethods);
         $this->xmlRootName = $object->xmlRootName;
+        $this->xmlRootNamespace = $object->xmlRootNamespace;
         $this->xmlNamespaces = array_merge($this->xmlNamespaces, $object->xmlNamespaces);
 
         // Handler methods are taken from the outer class completely.
@@ -218,6 +220,7 @@ class ClassMetadata extends MergeableClassMetadata
             $this->postSerializeMethods,
             $this->postDeserializeMethods,
             $this->xmlRootName,
+            $this->xmlRootNamespace,
             $this->xmlNamespaces,
             $this->accessorOrder,
             $this->customOrder,
@@ -238,6 +241,7 @@ class ClassMetadata extends MergeableClassMetadata
             $this->postSerializeMethods,
             $this->postDeserializeMethods,
             $this->xmlRootName,
+            $this->xmlRootNamespace,
             $this->xmlNamespaces,
             $this->accessorOrder,
             $this->customOrder,

+ 1 - 0
src/JMS/Serializer/Metadata/Driver/AnnotationDriver.php

@@ -82,6 +82,7 @@ class AnnotationDriver implements DriverInterface
                 $exclusionPolicy = $annot->policy;
             } elseif ($annot instanceof XmlRoot) {
                 $classMetadata->xmlRootName = $annot->name;
+                $classMetadata->xmlRootNamespace = $annot->namespace;
             } elseif ($annot instanceof XmlNamespace) {
                 $classMetadata->registerNamespace($annot->uri, $annot->prefix);
             } elseif ($annot instanceof Exclude) {

+ 4 - 0
src/JMS/Serializer/Metadata/Driver/XmlDriver.php

@@ -63,6 +63,10 @@ class XmlDriver extends AbstractFileDriver
             $metadata->xmlRootName = (string) $xmlRootName;
         }
 
+        if (null !== $xmlRootNamespace = $elem->attributes()->{'xml-root-namespace'}) {
+            $metadata->xmlRootNamespace = (string) $xmlRootNamespace;
+        }
+
         $readOnlyClass = 'true' === strtolower($elem->attributes()->{'read-only'});
 
         $discriminatorFieldName = (string) $elem->attributes()->{'discriminator-field-name'};

+ 4 - 0
src/JMS/Serializer/Metadata/Driver/YamlDriver.php

@@ -238,6 +238,10 @@ class YamlDriver extends AbstractFileDriver
             $metadata->xmlRootName = (string) $config['xml_root_name'];
         }
 
+        if (isset($config['xml_root_namespace'])) {
+            $metadata->xmlRootNamespace = (string) $config['xml_root_namespace'];
+        }
+
         if (array_key_exists('xml_namespaces', $config) ) {
 
             foreach ( $config['xml_namespaces'] as $prefix => $uri) {

+ 22 - 3
src/JMS/Serializer/XmlSerializationVisitor.php

@@ -33,6 +33,7 @@ class XmlSerializationVisitor extends AbstractVisitor
 
     private $navigator;
     private $defaultRootName = 'result';
+    private $defaultRootNamespace;
     private $defaultVersion = '1.0';
     private $defaultEncoding = 'UTF-8';
     private $stack;
@@ -42,9 +43,10 @@ class XmlSerializationVisitor extends AbstractVisitor
     private $hasValue;
     private $nullWasVisited;
 
-    public function setDefaultRootName($name)
+    public function setDefaultRootName($name, $namespace = null)
     {
         $this->defaultRootName = $name;
+        $this->defaultRootNamespace = $namespace;
     }
 
     /**
@@ -183,7 +185,19 @@ class XmlSerializationVisitor extends AbstractVisitor
     {
         if (null === $this->document) {
             $this->document = $this->createDocument(null, null, false);
-            $this->document->appendChild($this->currentNode = $this->document->createElement($metadata->xmlRootName ?: $this->defaultRootName));
+            if ($metadata->xmlRootName) {
+                $rootName = $metadata->xmlRootName;
+                $rootNamespace = $metadata->xmlRootNamespace;
+            } else {
+                $rootName = $this->defaultRootName;
+                $rootNamespace = $this->defaultRootNamespace;
+            }
+            if ($rootNamespace) {
+                $this->currentNode = $this->document->createElementNS($rootNamespace, $rootName);
+            } else {
+                $this->currentNode = $this->document->createElement($rootName);
+            }
+            $this->document->appendChild($this->currentNode);
         }
         
         $this->addNamespaceAttributes($metadata, $this->currentNode);
@@ -353,7 +367,12 @@ class XmlSerializationVisitor extends AbstractVisitor
         $doc->formatOutput = true;
 
         if ($addRoot) {
-            $this->setCurrentNode($rootNode = $doc->createElement($this->defaultRootName));
+            if ($this->defaultRootNamespace) {
+                $rootNode = $doc->createElementNS($this->defaultRootNamespace, $this->defaultRootName);
+            } else {
+                $rootNode = $doc->createElement($this->defaultRootName);
+            }
+            $this->setCurrentNode($rootNode);
             $doc->appendChild($rootNode);
         }
 

+ 2 - 2
tests/JMS/Serializer/Tests/Fixtures/ObjectWithXmlNamespaces.php

@@ -25,7 +25,7 @@ use JMS\Serializer\Annotation\XmlElement;
 use JMS\Serializer\Annotation\XmlAttribute;
 
 /**
- * @XmlRoot("test-object")
+ * @XmlRoot("test-object", namespace="http://example.com/namespace")
  * @XmlNamespace(uri="http://example.com/namespace")
  * @XmlNamespace(uri="http://schemas.google.com/g/2005", prefix="gd")
  * @XmlNamespace(uri="http://www.w3.org/2005/Atom", prefix="atom")
@@ -70,4 +70,4 @@ class ObjectWithXmlNamespaces
         $this->language = $language;
         $this->etag = sha1($this->createdAt->format(\DateTime::ISO8601));
     }
-}
+}

+ 68 - 0
tests/JMS/Serializer/Tests/Fixtures/ObjectWithXmlRootNamespace.php

@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * Copyright 2013 Johannes M. Schmitt <schmittjoh@gmail.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace JMS\Serializer\Tests\Fixtures;
+
+use JMS\Serializer\Annotation\Type;
+use JMS\Serializer\Annotation\XmlRoot;
+use JMS\Serializer\Annotation\XmlNamespace;
+use JMS\Serializer\Annotation\XmlElement;
+use JMS\Serializer\Annotation\XmlAttribute;
+
+/**
+ * @XmlRoot("test-object", namespace="http://example.com/namespace")
+ */
+class ObjectWithXmlRootNamespace
+{
+    /**
+     * @Type("string")
+     */
+    private $title;
+
+    /**
+     * @Type("DateTime")
+     * @XmlAttribute
+     */
+    private $createdAt;
+
+    /**
+     * @Type("string")
+     * @XmlAttribute
+     */
+    private $etag;
+
+    /**
+     * @Type("string")
+     */
+    private $author;
+    
+    /**
+     * @Type("string")
+     * @XmlAttribute
+     */
+    private $language;
+
+    public function __construct($title, $author, \DateTime $createdAt, $language)
+    {
+        $this->title = $title;
+        $this->author = $author;
+        $this->createdAt = $createdAt;
+        $this->language = $language;
+        $this->etag = sha1($this->createdAt->format(\DateTime::ISO8601));
+    }
+}

+ 1 - 0
tests/JMS/Serializer/Tests/Metadata/Driver/BaseDriverTest.php

@@ -174,6 +174,7 @@ abstract class BaseDriverTest extends \PHPUnit_Framework_TestCase
         $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces'));
         $this->assertNotNull($m);
         $this->assertEquals('test-object', $m->xmlRootName);
+        $this->assertEquals('http://example.com/namespace', $m->xmlRootNamespace);
         $this->assertCount(3, $m->xmlNamespaces);
         $this->assertArrayHasKey('', $m->xmlNamespaces);
         $this->assertEquals('http://example.com/namespace', $m->xmlNamespaces['']);

+ 2 - 1
tests/JMS/Serializer/Tests/Metadata/Driver/php/ObjectWithXmlNamespaces.php

@@ -5,6 +5,7 @@ use JMS\Serializer\Metadata\PropertyMetadata;
 
 $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces');
 $metadata->xmlRootName = 'test-object';
+$metadata->xmlRootNamespace = 'http://example.com/namespace';
 
 $metadata->registerNamespace('http://example.com/namespace');
 $metadata->registerNamespace('http://schemas.google.com/g/2005', 'gd');
@@ -37,4 +38,4 @@ $pMetadata->xmlAttribute = true;
 $pMetadata->xmlNamespace = 'http://purl.org/dc/elements/1.1/';
 $metadata->addPropertyMetadata($pMetadata);
 
-return $metadata;
+return $metadata;

+ 2 - 2
tests/JMS/Serializer/Tests/Metadata/Driver/xml/ObjectWithXmlNamespaces.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <serializer>
-    <class name="JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces" xml-root-name="test-object">
+    <class name="JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces" xml-root-name="test-object" xml-root-namespace="http://example.com/namespace">
         <xml-namespace uri="http://example.com/namespace"/>
         <xml-namespace prefix="gd" uri="http://schemas.google.com/g/2005"/>
         <xml-namespace prefix="atom" uri="http://www.w3.org/2005/Atom"/>
@@ -18,4 +18,4 @@
             <xml-element namespace="http://purl.org/dc/elements/1.1/"/>
         </property>
     </class>
-</serializer>
+</serializer>

+ 2 - 1
tests/JMS/Serializer/Tests/Metadata/Driver/yml/ObjectWithXmlNamespaces.yml

@@ -1,5 +1,6 @@
 JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces:
     xml_root_name: test-object
+    xml_root_namespace: http://example.com/namespace
     xml_namespaces:
         "": http://example.com/namespace
         gd: http://schemas.google.com/g/2005
@@ -25,4 +26,4 @@ JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces:
             type: string
             xml_attribute: true
             xml_element:
-                namespace: http://purl.org/dc/elements/1.1/
+                namespace: http://purl.org/dc/elements/1.1/

+ 7 - 0
tests/JMS/Serializer/Tests/Serializer/XmlSerializationTest.php

@@ -31,6 +31,7 @@ use JMS\Serializer\Tests\Fixtures\Person;
 use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualXmlProperties;
 use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs;
 use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces;
+use JMS\Serializer\Tests\Fixtures\ObjectWithXmlRootNamespace;
 use JMS\Serializer\Tests\Fixtures\Input;
 use JMS\Serializer\Tests\Fixtures\SimpleClassObject;
 use JMS\Serializer\Tests\Fixtures\SimpleSubClassObject;
@@ -208,6 +209,12 @@ class XmlSerializationTest extends BaseSerializationTest
 
     }
 
+    public function testObjectWithXmlRootNamespace()
+    {
+        $object = new ObjectWithXmlRootNamespace('This is a nice title.', 'Foo Bar', new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), 'en');
+        $this->assertEquals($this->getContent('object_with_xml_root_namespace'), $this->serialize($object));
+    }
+
     public function testXmlNamespacesInheritance()
     {
         $object = new SimpleClassObject();

+ 5 - 0
tests/JMS/Serializer/Tests/Serializer/xml/object_with_xml_root_namespace.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test-object xmlns="http://example.com/namespace" created_at="2011-07-30T00:00:00+0000" etag="1edf9bf60a32d89afbb85b2be849e3ceed5f5b10" language="en">
+  <title><![CDATA[This is a nice title.]]></title>
+  <author><![CDATA[Foo Bar]]></author>
+</test-object>