Skip to content
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
2 changes: 2 additions & 0 deletions doc/reference/annotations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ Resulting XML:
</comment>
</post>

You can also specify the entry tag namespace using the ``namespace`` attribute (``@XmlList(inline = true, entry = "comment", namespace="http://www.example.com/ns")``).

@XmlMap
~~~~~~~
Similar to @XmlList, but the keys of the array are meaningful.
Expand Down
2 changes: 1 addition & 1 deletion doc/reference/xml_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ XML Reference
your type contains "<" or ">" characters. -->
<type><![CDATA[]]></type>
<xml-list inline="true" entry-name="foobar" />
<xml-map inline="true" key-attribute-name="foo" entry-name="bar" />
<xml-map inline="true" key-attribute-name="foo" entry-name="bar" namespace="http://www.w3.org/2005/Atom" />
<xml-element cdata="false" namespace="http://www.w3.org/2005/Atom"/>
</property>
<callback-method name="foo" type="pre-serialize" />
Expand Down
2 changes: 2 additions & 0 deletions doc/reference/yml_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ YAML Reference
xml_list:
inline: true
entry_name: foo
namespace: http://www.w3.org/2005/Atom
xml_map:
inline: true
key_attribute_name: foo
entry_name: bar
namespace: http://www.w3.org/2005/Atom
xml_attribute_map: true
xml_element:
cdata: false
Expand Down
5 changes: 5 additions & 0 deletions src/JMS/Serializer/Annotation/XmlCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ abstract class XmlCollection
* @var boolean
*/
public $inline = false;

/**
* @var string
*/
public $namespace;
}
2 changes: 2 additions & 0 deletions src/JMS/Serializer/Metadata/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,12 @@ public function loadMetadataForClass(\ReflectionClass $class)
$propertyMetadata->xmlCollection = true;
$propertyMetadata->xmlCollectionInline = $annot->inline;
$propertyMetadata->xmlEntryName = $annot->entry;
$propertyMetadata->xmlEntryNamespace = $annot->namespace;
} elseif ($annot instanceof XmlMap) {
$propertyMetadata->xmlCollection = true;
$propertyMetadata->xmlCollectionInline = $annot->inline;
$propertyMetadata->xmlEntryName = $annot->entry;
$propertyMetadata->xmlEntryNamespace = $annot->namespace;
$propertyMetadata->xmlKeyAttribute = $annot->keyAttribute;
} elseif ($annot instanceof XmlKeyValuePairs) {
$propertyMetadata->xmlKeyValuePairs = true;
Expand Down
8 changes: 8 additions & 0 deletions src/JMS/Serializer/Metadata/Driver/XmlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ protected function loadMetadataFromFile(\ReflectionClass $class, $path)
if (isset($colConfig->attributes()->{'entry-name'})) {
$pMetadata->xmlEntryName = (string) $colConfig->attributes()->{'entry-name'};
}

if (isset($colConfig->attributes()->namespace)) {
$pMetadata->xmlEntryNamespace = (string) $colConfig->attributes()->namespace;
}
}

if (isset($pElem->{'xml-map'})) {
Expand All @@ -186,6 +190,10 @@ protected function loadMetadataFromFile(\ReflectionClass $class, $path)
$pMetadata->xmlEntryName = (string) $colConfig->attributes()->{'entry-name'};
}

if (isset($colConfig->attributes()->namespace)) {
$pMetadata->xmlEntryNamespace = (string) $colConfig->attributes()->namespace;
}

if (isset($colConfig->attributes()->{'key-attribute-name'})) {
$pMetadata->xmlKeyAttribute = (string) $colConfig->attributes()->{'key-attribute-name'};
}
Expand Down
9 changes: 9 additions & 0 deletions src/JMS/Serializer/Metadata/Driver/YamlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ protected function loadMetadataFromFile(\ReflectionClass $class, $file)
if (isset($colConfig['entry_name'])) {
$pMetadata->xmlEntryName = (string) $colConfig['entry_name'];
}

if (isset($colConfig['namespace'])) {
$pMetadata->xmlEntryNamespace = (string) $colConfig['namespace'];
}
}

if (isset($pConfig['xml_map'])) {
Expand All @@ -133,9 +137,14 @@ protected function loadMetadataFromFile(\ReflectionClass $class, $file)
$pMetadata->xmlEntryName = (string) $colConfig['entry_name'];
}

if (isset($colConfig['namespace'])) {
$pMetadata->xmlEntryNamespace = (string) $colConfig['namespace'];
}

if (isset($colConfig['key_attribute_name'])) {
$pMetadata->xmlKeyAttribute = $colConfig['key_attribute_name'];
}

}

if (isset($pConfig['xml_element'])) {
Expand Down
10 changes: 9 additions & 1 deletion src/JMS/Serializer/Metadata/PropertyMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class PropertyMetadata extends BasePropertyMetadata
public $xmlCollection = false;
public $xmlCollectionInline = false;
public $xmlEntryName;
public $xmlEntryNamespace;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add that to serialize / unserialize a bit further down, no?

public $xmlKeyAttribute;
public $xmlAttribute = false;
public $xmlValue = false;
Expand Down Expand Up @@ -122,11 +123,13 @@ public function serialize()
$this->xmlAttributeMap,
$this->maxDepth,
parent::serialize(),
'xmlEntryNamespace' => $this->xmlEntryNamespace,
));
}

public function unserialize($str)
{
$unserialized = unserialize($str);
list(
$this->sinceVersion,
$this->untilVersion,
Expand All @@ -136,6 +139,7 @@ public function unserialize($str)
$this->xmlCollection,
$this->xmlCollectionInline,
$this->xmlEntryName,
$this->xmlEntryNamespace,
$this->xmlKeyAttribute,
$this->xmlAttribute,
$this->xmlValue,
Expand All @@ -149,7 +153,11 @@ public function unserialize($str)
$this->xmlAttributeMap,
$this->maxDepth,
$parentStr
) = unserialize($str);
) = $unserialized;

if (isset($unserialized['xmlEntryNamespace'])){
$this->xmlEntryNamespace = $unserialized['xmlEntryNamespace'];
}

parent::unserialize($parentStr);
}
Expand Down
83 changes: 46 additions & 37 deletions src/JMS/Serializer/XmlDeserializationVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class XmlDeserializationVisitor extends AbstractVisitor
{
private $objectStack;
private $metadataStack;
private $objectMetadataStack;
private $currentObject;
private $currentMetadata;
private $result;
Expand All @@ -46,6 +47,7 @@ public function setNavigator(GraphNavigator $navigator)
$this->navigator = $navigator;
$this->objectStack = new \SplStack;
$this->metadataStack = new \SplStack;
$this->objectMetadataStack = new \SplStack;
$this->result = null;
}

Expand Down Expand Up @@ -74,6 +76,7 @@ public function prepare($data)
}

$doc = simplexml_load_string($data);

libxml_use_internal_errors($previous);
libxml_disable_entity_loader($previousEntityLoaderState);

Expand Down Expand Up @@ -144,8 +147,14 @@ public function visitDouble($data, array $type, Context $context)
public function visitArray($data, array $type, Context $context)
{
$entryName = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryName ? $this->currentMetadata->xmlEntryName : 'entry';
$namespace = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryNamespace ? $this->currentMetadata->xmlEntryNamespace : null;

if ($namespace === null && $this->objectMetadataStack->count()) {
$classMetadata = $this->objectMetadataStack->top();
$namespace = isset($classMetadata->xmlNamespaces[''])?$classMetadata->xmlNamespaces['']:$namespace;
}

if ( ! isset($data->$entryName)) {
if ( ! isset($data->$entryName) ) {
if (null === $this->result) {
return $this->result = array();
}
Expand All @@ -159,11 +168,13 @@ public function visitArray($data, array $type, Context $context)

case 1:
$result = array();

if (null === $this->result) {
$this->result = &$result;
}

foreach ($data->$entryName as $v) {
$nodes = $data->children($namespace)->$entryName;
foreach ($nodes as $v) {
$result[] = $this->navigator->accept($v, $type['params'][0], $context);
}

Expand All @@ -180,12 +191,14 @@ public function visitArray($data, array $type, Context $context)
$this->result = &$result;
}

foreach ($data->$entryName as $v) {
if ( ! isset($v[$this->currentMetadata->xmlKeyAttribute])) {
$nodes = $data->children($namespace)->$entryName;
foreach ($nodes as $v) {
$attrs = $v->attributes();
if ( ! isset($attrs[$this->currentMetadata->xmlKeyAttribute])) {
throw new RuntimeException(sprintf('The key attribute "%s" must be set for each entry of the map.', $this->currentMetadata->xmlKeyAttribute));
}

$k = $this->navigator->accept($v[$this->currentMetadata->xmlKeyAttribute], $keyType, $context);
$k = $this->navigator->accept($attrs[$this->currentMetadata->xmlKeyAttribute], $keyType, $context);
$result[$k] = $this->navigator->accept($v, $entryType, $context);
}

Expand All @@ -199,7 +212,7 @@ public function visitArray($data, array $type, Context $context)
public function startVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context)
{
$this->setCurrentObject($object);

$this->objectMetadataStack->push($metadata);
if (null === $this->result) {
$this->result = $this->currentObject;
}
Expand All @@ -213,22 +226,11 @@ public function visitProperty(PropertyMetadata $metadata, $data, Context $contex
throw new RuntimeException(sprintf('You must define a type for %s::$%s.', $metadata->reflection->class, $metadata->name));
}

if ($metadata->xmlAttribute) {
if ('' !== $namespace = (string) $metadata->xmlNamespace) {
$registeredNamespaces = $data->getDocNamespaces();
if (false === $prefix = array_search($namespace, $registeredNamespaces)) {
$prefix = uniqid('ns-');
$data->registerXPathNamespace($prefix, $namespace);
}
$attributeName = ($prefix === '') ? $name : $prefix.':'.$name;
$nodes = $data->xpath('./@'.$attributeName);
if ( ! empty($nodes)) {
$v = (string) reset($nodes);
$metadata->reflection->setValue($this->currentObject, $v);
}
if ($metadata->xmlAttribute) {

} elseif (isset($data[$name])) {
$v = $this->navigator->accept($data[$name], $metadata->type, $context);
$attributes = $data->attributes($metadata->xmlNamespace);
if (isset($attributes[$name])) {
$v = $this->navigator->accept($attributes[$name], $metadata->type, $context);
$metadata->reflection->setValue($this->currentObject, $v);
}

Expand All @@ -244,8 +246,8 @@ public function visitProperty(PropertyMetadata $metadata, $data, Context $contex

if ($metadata->xmlCollection) {
$enclosingElem = $data;
if ( ! $metadata->xmlCollectionInline && isset($data->$name)) {
$enclosingElem = $data->$name;
if (!$metadata->xmlCollectionInline) {
$enclosingElem = $data->children($metadata->xmlNamespace)->$name;
}

$this->setCurrentMetadata($metadata);
Expand All @@ -256,23 +258,29 @@ public function visitProperty(PropertyMetadata $metadata, $data, Context $contex
return;
}

if ('' !== $namespace = (string) $metadata->xmlNamespace) {
$registeredNamespaces = $data->getDocNamespaces();
if (false === $prefix = array_search($namespace, $registeredNamespaces)) {
$prefix = uniqid('ns-');
$data->registerXPathNamespace($prefix, $namespace);
}
$elementName = ($prefix === '') ? $name : $prefix.':'.$name;
$nodes = $data->xpath('./'.$elementName);
if (empty($nodes)) {
if ($metadata->xmlNamespace) {
$node = $data->children($metadata->xmlNamespace)->$name;
if (!$node->count()) {
return;
}
$node = reset($nodes);
} else {
if ( ! isset($data->$name)) {
return;

$namespaces = $data->getDocNamespaces();

if (isset($namespaces[''])) {
$prefix = uniqid('ns-');
$data->registerXPathNamespace($prefix, $namespaces['']);
$nodes = $data->xpath('./'.$prefix. ':'.$name );
if (empty($nodes)) {
return;
}
$node = reset($nodes);
} else {
if (!isset($data->$name)) {
return;
}
$node = $data->$name;
}
$node = $data->$name;
}

$v = $this->navigator->accept($node, $metadata->type, $context);
Expand All @@ -289,6 +297,7 @@ public function visitProperty(PropertyMetadata $metadata, $data, Context $contex
public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
{
$rs = $this->currentObject;
$this->objectMetadataStack->pop();
$this->revertCurrentObject();

return $rs;
Expand Down Expand Up @@ -359,7 +368,7 @@ private function getDomDocumentTypeEntitySubset(\DOMDocumentType $child, $data)
if (null !== $child->internalSubset) {
return str_replace(array("\n", "\r"), '', $child->internalSubset);
}

$startPos = $endPos = stripos($data, '<!doctype');
$braces = 0;
do {
Expand Down
Loading