Exception
11 months ago
AbstractParser.php
11 months ago
AbstractRestParser.php
11 months ago
Crc32ValidatingParser.php
11 months ago
DecodingEventStreamIterator.php
11 months ago
EventParsingIterator.php
11 months ago
JsonParser.php
11 months ago
JsonRpcParser.php
11 months ago
MetadataParserTrait.php
11 months ago
PayloadParserTrait.php
11 months ago
QueryParser.php
11 months ago
RestJsonParser.php
11 months ago
RestXmlParser.php
11 months ago
XmlParser.php
11 months ago
XmlParser.php
180 lines
| 1 | <?php |
| 2 | namespace Aws\Api\Parser; |
| 3 | |
| 4 | use Aws\Api\DateTimeResult; |
| 5 | use Aws\Api\ListShape; |
| 6 | use Aws\Api\MapShape; |
| 7 | use Aws\Api\Parser\Exception\ParserException; |
| 8 | use Aws\Api\Shape; |
| 9 | use Aws\Api\StructureShape; |
| 10 | |
| 11 | /** |
| 12 | * @internal Implements standard XML parsing for REST-XML and Query protocols. |
| 13 | */ |
| 14 | class XmlParser |
| 15 | { |
| 16 | public function parse(StructureShape $shape, \SimpleXMLElement $value) |
| 17 | { |
| 18 | return $this->dispatch($shape, $value); |
| 19 | } |
| 20 | |
| 21 | private function dispatch($shape, \SimpleXMLElement $value) |
| 22 | { |
| 23 | static $methods = [ |
| 24 | 'structure' => 'parse_structure', |
| 25 | 'list' => 'parse_list', |
| 26 | 'map' => 'parse_map', |
| 27 | 'blob' => 'parse_blob', |
| 28 | 'boolean' => 'parse_boolean', |
| 29 | 'integer' => 'parse_integer', |
| 30 | 'float' => 'parse_float', |
| 31 | 'double' => 'parse_float', |
| 32 | 'timestamp' => 'parse_timestamp', |
| 33 | ]; |
| 34 | |
| 35 | $type = $shape['type']; |
| 36 | if (isset($methods[$type])) { |
| 37 | return $this->{$methods[$type]}($shape, $value); |
| 38 | } |
| 39 | |
| 40 | return (string) $value; |
| 41 | } |
| 42 | |
| 43 | private function parse_structure( |
| 44 | StructureShape $shape, |
| 45 | \SimpleXMLElement $value |
| 46 | ) { |
| 47 | $target = []; |
| 48 | |
| 49 | foreach ($shape->getMembers() as $name => $member) { |
| 50 | // Extract the name of the XML node |
| 51 | $node = $this->memberKey($member, $name); |
| 52 | if (isset($value->{$node})) { |
| 53 | $target[$name] = $this->dispatch($member, $value->{$node}); |
| 54 | } else { |
| 55 | $memberShape = $shape->getMember($name); |
| 56 | if (!empty($memberShape['xmlAttribute'])) { |
| 57 | $target[$name] = $this->parse_xml_attribute( |
| 58 | $shape, |
| 59 | $memberShape, |
| 60 | $value |
| 61 | ); |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | if (isset($shape['union']) |
| 66 | && $shape['union'] |
| 67 | && empty($target) |
| 68 | ) { |
| 69 | foreach ($value as $key => $val) { |
| 70 | $name = $val->children()->getName(); |
| 71 | $target['Unknown'][$name] = $val->$name; |
| 72 | } |
| 73 | } |
| 74 | return $target; |
| 75 | } |
| 76 | |
| 77 | private function memberKey(Shape $shape, $name) |
| 78 | { |
| 79 | if (null !== $shape['locationName']) { |
| 80 | return $shape['locationName']; |
| 81 | } |
| 82 | |
| 83 | if ($shape instanceof ListShape && $shape['flattened']) { |
| 84 | return $shape->getMember()['locationName'] ?: $name; |
| 85 | } |
| 86 | |
| 87 | return $name; |
| 88 | } |
| 89 | |
| 90 | private function parse_list(ListShape $shape, \SimpleXMLElement $value) |
| 91 | { |
| 92 | $target = []; |
| 93 | $member = $shape->getMember(); |
| 94 | |
| 95 | if (!$shape['flattened']) { |
| 96 | $value = $value->{$member['locationName'] ?: 'member'}; |
| 97 | } |
| 98 | |
| 99 | foreach ($value as $v) { |
| 100 | $target[] = $this->dispatch($member, $v); |
| 101 | } |
| 102 | |
| 103 | return $target; |
| 104 | } |
| 105 | |
| 106 | private function parse_map(MapShape $shape, \SimpleXMLElement $value) |
| 107 | { |
| 108 | $target = []; |
| 109 | |
| 110 | if (!$shape['flattened']) { |
| 111 | $value = $value->entry; |
| 112 | } |
| 113 | |
| 114 | $mapKey = $shape->getKey(); |
| 115 | $mapValue = $shape->getValue(); |
| 116 | $keyName = $shape->getKey()['locationName'] ?: 'key'; |
| 117 | $valueName = $shape->getValue()['locationName'] ?: 'value'; |
| 118 | |
| 119 | foreach ($value as $node) { |
| 120 | $key = $this->dispatch($mapKey, $node->{$keyName}); |
| 121 | $value = $this->dispatch($mapValue, $node->{$valueName}); |
| 122 | $target[$key] = $value; |
| 123 | } |
| 124 | |
| 125 | return $target; |
| 126 | } |
| 127 | |
| 128 | private function parse_blob(Shape $shape, $value) |
| 129 | { |
| 130 | return base64_decode((string) $value); |
| 131 | } |
| 132 | |
| 133 | private function parse_float(Shape $shape, $value) |
| 134 | { |
| 135 | return (float) (string) $value; |
| 136 | } |
| 137 | |
| 138 | private function parse_integer(Shape $shape, $value) |
| 139 | { |
| 140 | return (int) (string) $value; |
| 141 | } |
| 142 | |
| 143 | private function parse_boolean(Shape $shape, $value) |
| 144 | { |
| 145 | return $value == 'true'; |
| 146 | } |
| 147 | |
| 148 | private function parse_timestamp(Shape $shape, $value) |
| 149 | { |
| 150 | if (is_string($value) |
| 151 | || is_int($value) |
| 152 | || (is_object($value) |
| 153 | && method_exists($value, '__toString')) |
| 154 | ) { |
| 155 | return DateTimeResult::fromTimestamp( |
| 156 | (string) $value, |
| 157 | !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null |
| 158 | ); |
| 159 | } |
| 160 | throw new ParserException('Invalid timestamp value passed to XmlParser::parse_timestamp'); |
| 161 | } |
| 162 | |
| 163 | private function parse_xml_attribute(Shape $shape, Shape $memberShape, $value) |
| 164 | { |
| 165 | $namespace = $shape['xmlNamespace']['uri'] |
| 166 | ? $shape['xmlNamespace']['uri'] |
| 167 | : ''; |
| 168 | $prefix = $shape['xmlNamespace']['prefix'] |
| 169 | ? $shape['xmlNamespace']['prefix'] |
| 170 | : ''; |
| 171 | if (!empty($prefix)) { |
| 172 | $prefix .= ':'; |
| 173 | } |
| 174 | $key = str_replace($prefix, '', $memberShape['locationName']); |
| 175 | |
| 176 | $attributes = $value->attributes($namespace); |
| 177 | return isset($attributes[$key]) ? (string) $attributes[$key] : null; |
| 178 | } |
| 179 | } |
| 180 |