namespace Symfony\Component\Serializer\Encoder;
-use Symfony\Component\Serializer\Exception\UnexpectedValueException;
+use Symfony\Component\Serializer\Exception\NotEncodableValueException;
/**
* Encodes XML data.
*/
class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, DecoderInterface, NormalizationAwareInterface
{
+ const FORMAT = 'xml';
+
/**
* @var \DOMDocument
*/
public function decode($data, $format, array $context = array())
{
if ('' === trim($data)) {
- throw new UnexpectedValueException('Invalid XML data, it can not be empty.');
+ throw new NotEncodableValueException('Invalid XML data, it can not be empty.');
}
$internalErrors = libxml_use_internal_errors(true);
if ($error = libxml_get_last_error()) {
libxml_clear_errors();
- throw new UnexpectedValueException($error->message);
+ throw new NotEncodableValueException($error->message);
}
$rootNode = null;
foreach ($dom->childNodes as $child) {
- if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
- throw new UnexpectedValueException('Document types are not allowed.');
+ if (XML_DOCUMENT_TYPE_NODE === $child->nodeType) {
+ throw new NotEncodableValueException('Document types are not allowed.');
}
- if (!$rootNode && $child->nodeType !== XML_PI_NODE) {
+ if (!$rootNode && XML_PI_NODE !== $child->nodeType) {
$rootNode = $child;
}
}
unset($data['@xmlns:xml']);
if (empty($data)) {
- return $this->parseXml($rootNode);
+ return $this->parseXml($rootNode, $context);
}
- return array_merge($data, (array) $this->parseXml($rootNode));
+ return array_merge($data, (array) $this->parseXml($rootNode, $context));
}
if (!$rootNode->hasAttributes()) {
*/
public function supportsEncoding($format)
{
- return 'xml' === $format;
+ return self::FORMAT === $format;
}
/**
*/
public function supportsDecoding($format)
{
- return 'xml' === $format;
+ return self::FORMAT === $format;
}
/**
* Sets the root node name.
*
- * @param string $name root node name
+ * @param string $name Root node name
*/
public function setRootNodeName($name)
{
*/
final protected function appendXMLString(\DOMNode $node, $val)
{
- if (strlen($val) > 0) {
+ if (\strlen($val) > 0) {
$frag = $this->dom->createDocumentFragment();
$frag->appendXML($val);
$node->appendChild($frag);
/**
* Parse the input DOMNode into an array or a string.
*
- * @param \DOMNode $node xml to parse
- *
* @return array|string
*/
- private function parseXml(\DOMNode $node)
+ private function parseXml(\DOMNode $node, array $context = array())
{
- $data = $this->parseXmlAttributes($node);
+ $data = $this->parseXmlAttributes($node, $context);
- $value = $this->parseXmlValue($node);
+ $value = $this->parseXmlValue($node, $context);
- if (!count($data)) {
+ if (!\count($data)) {
return $value;
}
- if (!is_array($value)) {
+ if (!\is_array($value)) {
$data['#'] = $value;
return $data;
}
- if (1 === count($value) && key($value)) {
+ if (1 === \count($value) && key($value)) {
$data[key($value)] = current($value);
return $data;
/**
* Parse the input DOMNode attributes into an array.
*
- * @param \DOMNode $node xml to parse
- *
* @return array
*/
- private function parseXmlAttributes(\DOMNode $node)
+ private function parseXmlAttributes(\DOMNode $node, array $context = array())
{
if (!$node->hasAttributes()) {
return array();
}
$data = array();
+ $typeCastAttributes = $this->resolveXmlTypeCastAttributes($context);
foreach ($node->attributes as $attr) {
- if (!is_numeric($attr->nodeValue)) {
+ if (!is_numeric($attr->nodeValue) || !$typeCastAttributes) {
$data['@'.$attr->nodeName] = $attr->nodeValue;
continue;
/**
* Parse the input DOMNode value (content and children) into an array or a string.
*
- * @param \DOMNode $node xml to parse
- *
* @return array|string
*/
- private function parseXmlValue(\DOMNode $node)
+ private function parseXmlValue(\DOMNode $node, array $context = array())
{
if (!$node->hasChildNodes()) {
return $node->nodeValue;
}
- if (1 === $node->childNodes->length && in_array($node->firstChild->nodeType, array(XML_TEXT_NODE, XML_CDATA_SECTION_NODE))) {
+ if (1 === $node->childNodes->length && \in_array($node->firstChild->nodeType, array(XML_TEXT_NODE, XML_CDATA_SECTION_NODE))) {
return $node->firstChild->nodeValue;
}
$value = array();
foreach ($node->childNodes as $subnode) {
- if ($subnode->nodeType === XML_PI_NODE) {
+ if (XML_PI_NODE === $subnode->nodeType) {
continue;
}
- $val = $this->parseXml($subnode);
+ $val = $this->parseXml($subnode, $context);
if ('item' === $subnode->nodeName && isset($val['@key'])) {
if (isset($val['#'])) {
}
foreach ($value as $key => $val) {
- if (is_array($val) && 1 === count($val)) {
+ if (\is_array($val) && 1 === \count($val)) {
$value[$key] = current($val);
}
}
*
* @return bool
*
- * @throws UnexpectedValueException
+ * @throws NotEncodableValueException
*/
private function buildXml(\DOMNode $parentNode, $data, $xmlRootNodeName = null)
{
$append = true;
- if (is_array($data) || ($data instanceof \Traversable && !$this->serializer->supportsNormalization($data, $this->format))) {
+ if (\is_array($data) || ($data instanceof \Traversable && !$this->serializer->supportsNormalization($data, $this->format))) {
foreach ($data as $key => $data) {
//Ah this is the magic @ attribute types.
if (0 === strpos($key, '@') && $this->isElementNameValid($attributeName = substr($key, 1))) {
$data = $this->serializer->normalize($data, $this->format, $this->context);
}
$parentNode->setAttribute($attributeName, $data);
- } elseif ($key === '#') {
+ } elseif ('#' === $key) {
$append = $this->selectNodeType($parentNode, $data);
- } elseif (is_array($data) && false === is_numeric($key)) {
+ } elseif (\is_array($data) && false === is_numeric($key)) {
// Is this array fully numeric keys?
if (ctype_digit(implode('', array_keys($data)))) {
/*
}
} elseif (is_numeric($key) || !$this->isElementNameValid($key)) {
$append = $this->appendNode($parentNode, $data, 'item', $key);
- } else {
+ } elseif (null !== $data || !isset($this->context['remove_empty_tags']) || false === $this->context['remove_empty_tags']) {
$append = $this->appendNode($parentNode, $data, $key);
}
}
return $append;
}
- if (is_object($data)) {
+ if (\is_object($data)) {
$data = $this->serializer->normalize($data, $this->format, $this->context);
if (null !== $data && !is_scalar($data)) {
return $this->buildXml($parentNode, $data, $xmlRootNodeName);
return $this->appendNode($parentNode, $data, 'data');
}
- throw new UnexpectedValueException(sprintf('An unexpected value could not be serialized: %s', var_export($data, true)));
+ throw new NotEncodableValueException(sprintf('An unexpected value could not be serialized: %s', var_export($data, true)));
}
/**
*
* @return bool
*
- * @throws UnexpectedValueException
+ * @throws NotEncodableValueException
*/
private function selectNodeType(\DOMNode $node, $val)
{
- if (is_array($val)) {
+ if (\is_array($val)) {
return $this->buildXml($node, $val);
} elseif ($val instanceof \SimpleXMLElement) {
$child = $this->dom->importNode(dom_import_simplexml($val), true);
$node->appendChild($child);
} elseif ($val instanceof \Traversable) {
$this->buildXml($node, $val);
- } elseif (is_object($val)) {
+ } elseif (\is_object($val)) {
return $this->selectNodeType($node, $this->serializer->normalize($val, $this->format, $this->context));
} elseif (is_numeric($val)) {
return $this->appendText($node, (string) $val);
- } elseif (is_string($val) && $this->needsCdataWrapping($val)) {
+ } elseif (\is_string($val) && $this->needsCdataWrapping($val)) {
return $this->appendCData($node, $val);
- } elseif (is_string($val)) {
+ } elseif (\is_string($val)) {
return $this->appendText($node, $val);
- } elseif (is_bool($val)) {
+ } elseif (\is_bool($val)) {
return $this->appendText($node, (int) $val);
} elseif ($val instanceof \DOMNode) {
$child = $this->dom->importNode($val, true);
/**
* Get real XML root node name, taking serializer options into account.
*
- * @param array $context
- *
* @return string
*/
private function resolveXmlRootName(array $context = array())
: $this->rootNodeName;
}
+ /**
+ * Get XML option for type casting attributes Defaults to true.
+ *
+ * @param array $context
+ *
+ * @return bool
+ */
+ private function resolveXmlTypeCastAttributes(array $context = array())
+ {
+ return isset($context['xml_type_cast_attributes'])
+ ? (bool) $context['xml_type_cast_attributes']
+ : true;
+ }
+
/**
* Create a DOM document, taking serializer options into account.
*
- * @param array $context options that the encoder has access to
+ * @param array $context Options that the encoder has access to
*
* @return \DOMDocument
*/