Skip to content
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

Added support for using the keys of an array as XML tag. #129

Merged
merged 1 commit into from
Jul 2, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Annotation/XmlKeyValuePairs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* Copyright 2011 Johannes M. Schmitt <[email protected]>
*
* 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\SerializerBundle\Annotation;

/**
* @Annotation
* @Target({"PROPERTY","METHOD"})
*/
final class XmlKeyValuePairs
{
}
5 changes: 4 additions & 1 deletion Metadata/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use JMS\SerializerBundle\Annotation\XmlAttribute;
use JMS\SerializerBundle\Annotation\XmlList;
use JMS\SerializerBundle\Annotation\XmlValue;
use JMS\SerializerBundle\Annotation\XmlKeyValuePairs;
use JMS\SerializerBundle\Annotation\PostSerialize;
use JMS\SerializerBundle\Annotation\PostDeserialize;
use JMS\SerializerBundle\Annotation\PreSerialize;
Expand Down Expand Up @@ -149,6 +150,8 @@ public function loadMetadataForClass(\ReflectionClass $class)
$propertyMetadata->xmlCollectionInline = $annot->inline;
$propertyMetadata->xmlEntryName = $annot->entry;
$propertyMetadata->xmlKeyAttribute = $annot->keyAttribute;
} else if ($annot instanceof XmlKeyValuePairs) {
$propertyMetadata->xmlKeyValuePairs = true;
} else if ($annot instanceof XmlAttribute) {
$propertyMetadata->xmlAttribute = true;
} else if ($annot instanceof XmlValue) {
Expand Down Expand Up @@ -177,4 +180,4 @@ public function loadMetadataForClass(\ReflectionClass $class)

return $classMetadata;
}
}
}
5 changes: 4 additions & 1 deletion Metadata/PropertyMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class PropertyMetadata extends BasePropertyMetadata
public $xmlKeyAttribute;
public $xmlAttribute = false;
public $xmlValue = false;
public $xmlKeyValuePairs = false;
public $getter;
public $setter;
public $inline = false;
Expand Down Expand Up @@ -83,6 +84,7 @@ public function serialize()
$this->xmlKeyAttribute,
$this->xmlAttribute,
$this->xmlValue,
$this->xmlKeyValuePairs,
$this->getter,
$this->setter,
$this->inline,
Expand All @@ -105,6 +107,7 @@ public function unserialize($str)
$this->xmlKeyAttribute,
$this->xmlAttribute,
$this->xmlValue,
$this->xmlKeyValuePairs,
$this->getter,
$this->setter,
$this->inline,
Expand All @@ -114,4 +117,4 @@ public function unserialize($str)

parent::unserialize($parentStr);
}
}
}
4 changes: 3 additions & 1 deletion Metadata/VirtualPropertyMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function serialize()
$this->xmlKeyAttribute,
$this->xmlAttribute,
$this->xmlValue,
$this->xmlKeyValuePairs,
$this->getter,
$this->setter,
$this->inline,
Expand All @@ -88,6 +89,7 @@ public function unserialize($str)
$this->xmlKeyAttribute,
$this->xmlAttribute,
$this->xmlValue,
$this->xmlKeyValuePairs,
$this->getter,
$this->setter,
$this->inline,
Expand All @@ -96,4 +98,4 @@ public function unserialize($str)
$this->name
) = unserialize($str);
}
}
}
50 changes: 29 additions & 21 deletions Resources/doc/reference/annotations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ PHP's ``version_compare`` function.

@Groups
~~~~~~~
This annotation can be defined on a property to specifiy to if the property
should be serialized when only serializing specific groups (see
This annotation can be defined on a property to specifiy to if the property
should be serialized when only serializing specific groups (see
:doc:`../cookbook/exclusion_strategies`).

@AccessType
Expand All @@ -66,12 +66,12 @@ set the value via reflection, but you may change this to use a public method ins
class User
{
private $name;

public function getName()
{
return $this->name;
}

public function setName($name)
{
$this->name = trim($name);
Expand All @@ -90,16 +90,16 @@ be called to retrieve, or set the value of the given property:
class User
{
private $id;

/** @Accessor(getter="getTrimmedName") */
private $name;

// ...
public function getTrimmedName()
{
return trim($this->name);
}

public function setName($name)
{
$this->name = $name;
Expand All @@ -108,25 +108,25 @@ be called to retrieve, or set the value of the given property:

@AccessorOrder
~~~~~~~~~~~~~~
This annotation can be defined on a class to control the order of properties. By
This annotation can be defined on a class to control the order of properties. By
default the order is undefined, but you may change it to either "alphabetical", or
"custom".

.. code-block :: php

<?php

/**
* @AccessorOrder("alphabetical")
*
/**
* @AccessorOrder("alphabetical")
*
* Resulting Property Order: id, name
*/
class User
{
private $id;
private $name;
}

/**
* @AccessorOrder("custom", custom = {"name", "id"})
*
Expand All @@ -141,7 +141,7 @@ default the order is undefined, but you may change it to either "alphabetical",
@Inline
~~~~~~~~
This annotation can be defined on a property to indicate that the data of the property
should be inlined.
should be inlined.

**Note**: This only works for serialization, the serializer will not be able to deserialize
objects with this annotation. Also, AccessorOrder will be using the name of the property
Expand Down Expand Up @@ -299,31 +299,31 @@ Resulting XML:
<result id="1">
<name><![CDATA[Johannes]]></name>
</result>

@XmlValue
~~~~~~~~~
This allows you to mark properties which should be set as the value of the
current element. Note that this has the limitation that any additional
current element. Note that this has the limitation that any additional
properties of that object must have the @XmlAttribute annotation.

.. code-block :: php

<?php

use JMS\SerializerBundle\Annotation\XmlAttribute;
use JMS\SerializerBundle\Annotation\XmlValue;
use JMS\SerializerBundle\Annotation\XmlRoot;

/** @XmlRoot("price") */
class Price
{
/** @XmlAttribute */
private $currency = 'EUR';

/** @XmlValue */
private $amount = 1.23;
}

Resulting XML:

.. code-block :: xml
Expand Down Expand Up @@ -380,4 +380,12 @@ Resulting XML:

@XmlMap
~~~~~~~
Similar to @XmlList, but the keys of the array are meaningful.
Similar to @XmlList, but the keys of the array are meaningful.

@XmlKeyValuePairs
~~~~~~~~~~~~~~~~~
This allows you to use the keys of an array as xml tags.

.. note ::

When a key is an invalid xml tag name (e.g. 1_foo) the tag name *entry* will be used instead of the key.
19 changes: 18 additions & 1 deletion Serializer/XmlSerializationVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ public function visitArray($data, $type)
$keyAttributeName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlKeyAttribute) ? $this->currentMetadata->xmlKeyAttribute : null;

foreach ($data as $k => $v) {
$entryNode = $this->document->createElement($entryName);
$tagName = (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs && $this->isElementNameValid($k)) ? $k : $entryName;

$entryNode = $this->document->createElement($tagName);
$this->currentNode->appendChild($entryNode);
$this->setCurrentNode($entryNode);

Expand Down Expand Up @@ -283,4 +285,19 @@ private function visitNumeric($data, $type)

return $this->document->createTextNode((string) $data);
}

/**
* Checks the name is a valid xml element name
*
* @param string $name
*
* @return Boolean
*/
private function isElementNameValid($name)
{
return $name &&
false === strpos($name, ' ') &&
preg_match('#^[\pL_][\pL0-9._-]*$#ui', $name);
}

}
30 changes: 30 additions & 0 deletions Tests/Fixtures/ObjectWithXmlKeyValuePairs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace JMS\SerializerBundle\Tests\Fixtures;

use JMS\SerializerBundle\Annotation\XmlKeyValuePairs;

class ObjectWithXmlKeyValuePairs
{
/**
* @var array
* @XmlKeyValuePairs
*/
private $array = array(
'key-one' => 'foo',
'key-two' => 1,
'nested-array' => array(
'bar' => 'foo',
),
'without-keys' => array(
1,
'test'
),
'mixed' => array(
'test',
'foo' => 'bar',
'1_foo' => 'bar'
),
1 => 'foo'
);
}
7 changes: 7 additions & 0 deletions Tests/Serializer/XmlSerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use JMS\SerializerBundle\Tests\Fixtures\PersonLocation;
use JMS\SerializerBundle\Tests\Fixtures\Person;
use JMS\SerializerBundle\Tests\Fixtures\ObjectWithVirtualXmlProperties;
use JMS\SerializerBundle\Tests\Fixtures\ObjectWithXmlKeyValuePairs;

class XmlSerializationTest extends BaseSerializationTest
{
Expand Down Expand Up @@ -102,6 +103,12 @@ public function testVirtualXmlMap() {
$this->assertEquals($this->getContent('virtual_properties_map'), $serializer->serialize(new ObjectWithVirtualXmlProperties(),'xml'));
}

public function testArrayKeyValues()
{
$serializer = $this->getSerializer();
$this->assertEquals($this->getContent('array_key_values'), $serializer->serialize(new ObjectWithXmlKeyValuePairs(), 'xml'));
}

protected function getContent($key)
{
if (!file_exists($file = __DIR__.'/xml/'.$key.'.xml')) {
Expand Down
20 changes: 20 additions & 0 deletions Tests/Serializer/xml/array_key_values.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<result>
<array>
<key-one><![CDATA[foo]]></key-one>
<key-two>1</key-two>
<nested-array>
<bar><![CDATA[foo]]></bar>
</nested-array>
<without-keys>
<entry>1</entry>
<entry><![CDATA[test]]></entry>
</without-keys>
<mixed>
<entry><![CDATA[test]]></entry>
<foo><![CDATA[bar]]></foo>
<entry><![CDATA[bar]]></entry>
</mixed>
<entry><![CDATA[foo]]></entry>
</array>
</result>