Skip to content

Commit

Permalink
XmlList and XmlMap Namespace support
Browse files Browse the repository at this point in the history
Adding support for namespace param for XmlList and XmlMap Metadata

@xmllist(entry="event", inline = true, namespace="http://mynamespace.net" )
  • Loading branch information
mfoti authored and goetas committed May 5, 2016
1 parent 2b16866 commit 3f46809
Show file tree
Hide file tree
Showing 20 changed files with 370 additions and 67 deletions.
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
1 change: 1 addition & 0 deletions 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;
public $xmlKeyAttribute;
public $xmlAttribute = false;
public $xmlValue = false;
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

0 comments on commit 3f46809

Please sign in to comment.