<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
use GuzzleHttp\Command\Result;
use GuzzleHttp\Command\ResultInterface;
use Psr\Http\Message\ResponseInterface;
class XmlLocation extends AbstractLocation
{
private $xml;
public function __construct($locationName = 'xml')
{
parent::__construct($locationName);
}
public function before(
ResultInterface $result,
ResponseInterface $response,
Parameter $model
) {
$this->xml = simplexml_load_string((string) $response->getBody());
return $result;
}
public function after(
ResultInterface $result,
ResponseInterface $response,
Parameter $model
) {
$additional = $model->getAdditionalProperties();
if ($additional instanceof Parameter &&
$additional->getLocation() == $this->locationName
) {
$result = new Result(array_merge(
$result->toArray(),
self::xmlToArray($this->xml)
));
}
$this->xml = null;
return $result;
}
public function visit(
ResultInterface $result,
ResponseInterface $response,
Parameter $param
) {
$sentAs = $param->getWireName();
$ns = null;
if (strstr($sentAs, ':')) {
list($ns, $sentAs) = explode(':', $sentAs);
}
if (count($this->xml->children($ns, true)->{$sentAs})) {
$result[$param->getName()] = $this->recursiveProcess(
$param,
$this->xml->children($ns, true)->{$sentAs}
);
}
return $result;
}
private function recursiveProcess(
Parameter $param,
\SimpleXMLElement $node
) {
$result = [];
$type = $param->getType();
if ($type == 'object') {
$result = $this->processObject($param, $node);
} elseif ($type == 'array') {
$result = $this->processArray($param, $node);
} else {
if ($node->children()->count() == 0) {
$result = (string) $node;
}
}
if (isset($result)) {
$result = $param->filter($result);
}
return $result;
}
private function processArray(Parameter $param, \SimpleXMLElement $node)
{
$items = $param->getItems();
$sentAs = $items->getWireName();
$result = [];
$ns = null;
if (strstr($sentAs, ':')) {
list($ns, $sentAs) = explode(':', $sentAs);
} else {
$ns = $items->getData('xmlNs');
}
if ($sentAs === null) {
foreach ($node as $child) {
$result[] = $this->recursiveProcess($items, $child);
}
} else {
<collection><foo></foo><foo></foo></collection>)
$children = $node->children($ns, true)->{$sentAs};
foreach ($children as $child) {
$result[] = $this->recursiveProcess($items, $child);
}
}
return $result;
}
private function processObject(Parameter $param, \SimpleXMLElement $node)
{
$result = $knownProps = $knownAttributes = [];
if ($properties = $param->getProperties()) {
foreach ($properties as $property) {
$name = $property->getName();
$sentAs = $property->getWireName();
$knownProps[$sentAs] = 1;
if (strpos($sentAs, ':')) {
list($ns, $sentAs) = explode(':', $sentAs);
} else {
$ns = $property->getData('xmlNs');
}
if ($property->getData('xmlAttribute')) {
$result[$name] = (string) $node->attributes($ns, true)->{$sentAs};
$knownAttributes[$sentAs] = 1;
} elseif (count($node->children($ns, true)->{$sentAs})) {
$childNode = $node->children($ns, true)->{$sentAs};
$result[$name] = $this->recursiveProcess(
$property,
$childNode
);
}
}
}
$additional = $param->getAdditionalProperties();
if ($additional instanceof Parameter) {
foreach ($node->children($additional->getData('xmlNs'), true) as $childNode) {
$sentAs = $childNode->getName();
if (!isset($knownProps[$sentAs])) {
$result[$sentAs] = $this->recursiveProcess(
$additional,
$childNode
);
}
}
} elseif ($additional === null || $additional === true) {
$array = array_diff_key(self::xmlToArray($node), $knownProps);
if (isset($array['@attributes']) && $knownAttributes) {
$array['@attributes'] = array_diff_key($array['@attributes'], $knownProps);
if (!$array['@attributes']) {
unset($array['@attributes']);
}
}
$result = array_merge($array, $result);
}
return $result;
}
private static function xmlToArray(
\SimpleXMLElement $xml,
$ns = null,
$nesting = 0
) {
$result = [];
$children = $xml->children($ns, true);
foreach ($children as $name => $child) {
$attributes = (array) $child->attributes($ns, true);
if (!isset($result[$name])) {
$childArray = self::xmlToArray($child, $ns, $nesting + 1);
$result[$name] = $attributes
? array_merge($attributes, $childArray)
: $childArray;
continue;
}
if (!is_array($result[$name])) {
$result[$name] = [$result[$name]];
} elseif (!isset($result[$name][0])) {
$firstResult = $result[$name];
$result[$name] = [];
$result[$name][] = $firstResult;
}
$childArray = self::xmlToArray($child, $ns, $nesting + 1);
if ($attributes) {
$result[$name][] = array_merge($attributes, $childArray);
} else {
$result[$name][] = $childArray;
}
}
$text = trim((string) $xml);
if ($text === '') {
$text = null;
}
$attributes = (array) $xml->attributes($ns, true);
if ($attributes) {
if ($text !== null) {
$result['value'] = $text;
}
$result = array_merge($attributes, $result);
} elseif ($text !== null) {
$result = $text;
}
if ($nesting == 0 && !is_array($result)) {
$result = [$result];
}
return $result;
}
}