初始化仓库
This commit is contained in:
302
vendor/guzzlehttp/guzzle-services/src/ResponseLocation/XmlLocation.php
vendored
Normal file
302
vendor/guzzlehttp/guzzle-services/src/ResponseLocation/XmlLocation.php
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
|
||||
|
||||
use GuzzleHttp\Command\Guzzle\Parameter;
|
||||
use GuzzleHttp\Command\Result;
|
||||
use GuzzleHttp\Command\ResultInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Extracts elements from an XML document
|
||||
*/
|
||||
class XmlLocation extends AbstractLocation
|
||||
{
|
||||
/** @var \SimpleXMLElement XML document being visited */
|
||||
private $xml;
|
||||
|
||||
/**
|
||||
* Set the name of the location
|
||||
*
|
||||
* @param string $locationName
|
||||
*/
|
||||
public function __construct($locationName = 'xml')
|
||||
{
|
||||
parent::__construct($locationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResultInterface
|
||||
*/
|
||||
public function before(
|
||||
ResultInterface $result,
|
||||
ResponseInterface $response,
|
||||
Parameter $model
|
||||
) {
|
||||
$this->xml = simplexml_load_string((string) $response->getBody());
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Result|ResultInterface
|
||||
*/
|
||||
public function after(
|
||||
ResultInterface $result,
|
||||
ResponseInterface $response,
|
||||
Parameter $model
|
||||
) {
|
||||
// Handle additional, undefined properties
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResultInterface
|
||||
*/
|
||||
public function visit(
|
||||
ResultInterface $result,
|
||||
ResponseInterface $response,
|
||||
Parameter $param
|
||||
) {
|
||||
$sentAs = $param->getWireName();
|
||||
$ns = null;
|
||||
if (null !== $sentAs && strstr($sentAs, ':')) {
|
||||
list($ns, $sentAs) = explode(':', $sentAs);
|
||||
}
|
||||
|
||||
// Process the primary property
|
||||
if (count($this->xml->children($ns, true)->{$sentAs})) {
|
||||
$result[$param->getName()] = $this->recursiveProcess(
|
||||
$param,
|
||||
$this->xml->children($ns, true)->{$sentAs}
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively process a parameter while applying filters
|
||||
*
|
||||
* @param Parameter $param API parameter being processed
|
||||
* @param \SimpleXMLElement $node Node being processed
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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 {
|
||||
// We are probably handling a flat data node (i.e. string or
|
||||
// integer), so let's check if it's childless, which indicates a
|
||||
// node containing plain text.
|
||||
if ($node->children()->count() == 0) {
|
||||
// Retrieve text from node
|
||||
$result = (string) $node;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out the value
|
||||
if (isset($result)) {
|
||||
$result = $param->filter($result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function processArray(Parameter $param, \SimpleXMLElement $node)
|
||||
{
|
||||
// Cast to an array if the value was a string, but should be an array
|
||||
$items = $param->getItems();
|
||||
$sentAs = $items->getWireName();
|
||||
$result = [];
|
||||
$ns = null;
|
||||
|
||||
if (null !== $sentAs && strstr($sentAs, ':')) {
|
||||
// Get namespace from the wire name
|
||||
list($ns, $sentAs) = explode(':', $sentAs);
|
||||
} else {
|
||||
// Get namespace from data
|
||||
$ns = $items->getData('xmlNs');
|
||||
}
|
||||
|
||||
if ($sentAs === null) {
|
||||
// A general collection of nodes
|
||||
foreach ($node as $child) {
|
||||
$result[] = $this->recursiveProcess($items, $child);
|
||||
}
|
||||
} else {
|
||||
// A collection of named, repeating nodes
|
||||
// (i.e. <collection><foo></foo><foo></foo></collection>)
|
||||
$children = $node->children($ns, true)->{$sentAs};
|
||||
foreach ($children as $child) {
|
||||
$result[] = $this->recursiveProcess($items, $child);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an object
|
||||
*
|
||||
* @param Parameter $param API parameter being parsed
|
||||
* @param \SimpleXMLElement $node Value to process
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function processObject(Parameter $param, \SimpleXMLElement $node)
|
||||
{
|
||||
$result = $knownProps = $knownAttributes = [];
|
||||
|
||||
// Handle known properties
|
||||
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')) {
|
||||
// Handle XML attributes
|
||||
$result[$name] = (string) $node->attributes($ns, true)->{$sentAs};
|
||||
$knownAttributes[$sentAs] = 1;
|
||||
} elseif (count($node->children($ns, true)->{$sentAs})) {
|
||||
// Found a child node matching wire name
|
||||
$childNode = $node->children($ns, true)->{$sentAs};
|
||||
$result[$name] = $this->recursiveProcess(
|
||||
$property,
|
||||
$childNode
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle additional, undefined properties
|
||||
$additional = $param->getAdditionalProperties();
|
||||
if ($additional instanceof Parameter) {
|
||||
// Process all child elements according to the given schema
|
||||
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) {
|
||||
// Blindly transform the XML into an array preserving as much data
|
||||
// as possible. Remove processed, aliased properties.
|
||||
$array = array_diff_key(self::xmlToArray($node), $knownProps);
|
||||
// Remove @attributes that were explicitly plucked from the
|
||||
// attributes list.
|
||||
if (isset($array['@attributes']) && $knownAttributes) {
|
||||
$array['@attributes'] = array_diff_key($array['@attributes'], $knownProps);
|
||||
if (!$array['@attributes']) {
|
||||
unset($array['@attributes']);
|
||||
}
|
||||
}
|
||||
|
||||
// Merge it together with the original result
|
||||
$result = array_merge($array, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an XML document to an array.
|
||||
*
|
||||
* @param int $nesting
|
||||
* @param null $ns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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;
|
||||
}
|
||||
// A child element with this name exists so we're assuming
|
||||
// that the node contains a list of elements
|
||||
if (!is_array($result[$name])) {
|
||||
$result[$name] = [$result[$name]];
|
||||
} elseif (!isset($result[$name][0])) {
|
||||
// Convert the first child into the first element of a numerically indexed array
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract text from node
|
||||
$text = trim((string) $xml);
|
||||
if ($text === '') {
|
||||
$text = null;
|
||||
}
|
||||
|
||||
// Process attributes
|
||||
$attributes = (array) $xml->attributes($ns, true);
|
||||
if ($attributes) {
|
||||
if ($text !== null) {
|
||||
$result['value'] = $text;
|
||||
}
|
||||
$result = array_merge($attributes, $result);
|
||||
} elseif ($text !== null) {
|
||||
$result = $text;
|
||||
}
|
||||
|
||||
// Make sure we're always returning an array
|
||||
if ($nesting == 0 && !is_array($result)) {
|
||||
$result = [$result];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user