XmlBody.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. namespace Aws\Api\Serializer;
  3. use Aws\Api\MapShape;
  4. use Aws\Api\Service;
  5. use Aws\Api\Shape;
  6. use Aws\Api\StructureShape;
  7. use Aws\Api\ListShape;
  8. use Aws\Api\TimestampShape;
  9. use XMLWriter;
  10. /**
  11. * @internal Formats the XML body of a REST-XML services.
  12. */
  13. class XmlBody
  14. {
  15. /** @var \Aws\Api\Service */
  16. private $api;
  17. /**
  18. * @param Service $api API being used to create the XML body.
  19. */
  20. public function __construct(Service $api)
  21. {
  22. $this->api = $api;
  23. }
  24. /**
  25. * Builds the XML body based on an array of arguments.
  26. *
  27. * @param Shape $shape Operation being constructed
  28. * @param array $args Associative array of arguments
  29. *
  30. * @return string
  31. */
  32. public function build(Shape $shape, array $args)
  33. {
  34. $xml = new XMLWriter();
  35. $xml->openMemory();
  36. $xml->startDocument('1.0', 'UTF-8');
  37. $this->format($shape, $shape['locationName'] ?: $shape['name'], $args, $xml);
  38. $xml->endDocument();
  39. return $xml->outputMemory();
  40. }
  41. private function startElement(Shape $shape, $name, XMLWriter $xml)
  42. {
  43. $xml->startElement($name);
  44. if ($ns = $shape['xmlNamespace']) {
  45. $xml->writeAttribute(
  46. isset($ns['prefix']) ? "xmlns:{$ns['prefix']}" : 'xmlns',
  47. $shape['xmlNamespace']['uri']
  48. );
  49. }
  50. }
  51. private function format(Shape $shape, $name, $value, XMLWriter $xml)
  52. {
  53. // Any method mentioned here has a custom serialization handler.
  54. static $methods = [
  55. 'add_structure' => true,
  56. 'add_list' => true,
  57. 'add_blob' => true,
  58. 'add_timestamp' => true,
  59. 'add_boolean' => true,
  60. 'add_map' => true,
  61. 'add_string' => true
  62. ];
  63. $type = 'add_' . $shape['type'];
  64. if (isset($methods[$type])) {
  65. $this->{$type}($shape, $name, $value, $xml);
  66. } else {
  67. $this->defaultShape($shape, $name, $value, $xml);
  68. }
  69. }
  70. private function defaultShape(Shape $shape, $name, $value, XMLWriter $xml)
  71. {
  72. $this->startElement($shape, $name, $xml);
  73. $xml->text($value);
  74. $xml->endElement();
  75. }
  76. private function add_structure(
  77. StructureShape $shape,
  78. $name,
  79. array $value,
  80. \XMLWriter $xml
  81. ) {
  82. $this->startElement($shape, $name, $xml);
  83. foreach ($this->getStructureMembers($shape, $value) as $k => $definition) {
  84. $this->format(
  85. $definition['member'],
  86. $definition['member']['locationName'] ?: $k,
  87. $definition['value'],
  88. $xml
  89. );
  90. }
  91. $xml->endElement();
  92. }
  93. private function getStructureMembers(StructureShape $shape, array $value)
  94. {
  95. $members = [];
  96. foreach ($value as $k => $v) {
  97. if ($v !== null && $shape->hasMember($k)) {
  98. $definition = [
  99. 'member' => $shape->getMember($k),
  100. 'value' => $v,
  101. ];
  102. if ($definition['member']['xmlAttribute']) {
  103. // array_unshift_associative
  104. $members = [$k => $definition] + $members;
  105. } else {
  106. $members[$k] = $definition;
  107. }
  108. }
  109. }
  110. return $members;
  111. }
  112. private function add_list(
  113. ListShape $shape,
  114. $name,
  115. array $value,
  116. XMLWriter $xml
  117. ) {
  118. $items = $shape->getMember();
  119. if ($shape['flattened']) {
  120. $elementName = $name;
  121. } else {
  122. $this->startElement($shape, $name, $xml);
  123. $elementName = $items['locationName'] ?: 'member';
  124. }
  125. foreach ($value as $v) {
  126. $this->format($items, $elementName, $v, $xml);
  127. }
  128. if (!$shape['flattened']) {
  129. $xml->endElement();
  130. }
  131. }
  132. private function add_map(
  133. MapShape $shape,
  134. $name,
  135. array $value,
  136. XMLWriter $xml
  137. ) {
  138. $xmlEntry = $shape['flattened'] ? $shape['locationName'] : 'entry';
  139. $xmlKey = $shape->getKey()['locationName'] ?: 'key';
  140. $xmlValue = $shape->getValue()['locationName'] ?: 'value';
  141. $this->startElement($shape, $name, $xml);
  142. foreach ($value as $key => $v) {
  143. $this->startElement($shape, $xmlEntry, $xml);
  144. $this->format($shape->getKey(), $xmlKey, $key, $xml);
  145. $this->format($shape->getValue(), $xmlValue, $v, $xml);
  146. $xml->endElement();
  147. }
  148. $xml->endElement();
  149. }
  150. private function add_blob(Shape $shape, $name, $value, XMLWriter $xml)
  151. {
  152. $this->startElement($shape, $name, $xml);
  153. $xml->writeRaw(base64_encode($value));
  154. $xml->endElement();
  155. }
  156. private function add_timestamp(
  157. TimestampShape $shape,
  158. $name,
  159. $value,
  160. XMLWriter $xml
  161. ) {
  162. $this->startElement($shape, $name, $xml);
  163. $timestampFormat = !empty($shape['timestampFormat'])
  164. ? $shape['timestampFormat']
  165. : 'iso8601';
  166. $xml->writeRaw(TimestampShape::format($value, $timestampFormat));
  167. $xml->endElement();
  168. }
  169. private function add_boolean(
  170. Shape $shape,
  171. $name,
  172. $value,
  173. XMLWriter $xml
  174. ) {
  175. $this->startElement($shape, $name, $xml);
  176. $xml->writeRaw($value ? 'true' : 'false');
  177. $xml->endElement();
  178. }
  179. private function add_string(
  180. Shape $shape,
  181. $name,
  182. $value,
  183. XMLWriter $xml
  184. ) {
  185. if ($shape['xmlAttribute']) {
  186. $xml->writeAttribute($shape['locationName'] ?: $name, $value);
  187. } else {
  188. $this->defaultShape($shape, $name, $value, $xml);
  189. }
  190. }
  191. }