| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 | <?phpnamespace Aws\Api\Serializer;use Aws\Api\MapShape;use Aws\Api\Service;use Aws\Api\Shape;use Aws\Api\StructureShape;use Aws\Api\ListShape;use Aws\Api\TimestampShape;use XMLWriter;/** * @internal Formats the XML body of a REST-XML services. */class XmlBody{    /** @var \Aws\Api\Service */    private $api;    /**     * @param Service $api API being used to create the XML body.     */    public function __construct(Service $api)    {        $this->api = $api;    }    /**     * Builds the XML body based on an array of arguments.     *     * @param Shape $shape Operation being constructed     * @param array $args  Associative array of arguments     *     * @return string     */    public function build(Shape $shape, array $args)    {        $xml = new XMLWriter();        $xml->openMemory();        $xml->startDocument('1.0', 'UTF-8');        $this->format($shape, $shape['locationName'] ?: $shape['name'], $args, $xml);        $xml->endDocument();        return $xml->outputMemory();    }    private function startElement(Shape $shape, $name, XMLWriter $xml)    {        $xml->startElement($name);        if ($ns = $shape['xmlNamespace']) {            $xml->writeAttribute(                isset($ns['prefix']) ? "xmlns:{$ns['prefix']}" : 'xmlns',                $shape['xmlNamespace']['uri']            );        }    }    private function format(Shape $shape, $name, $value, XMLWriter $xml)    {        // Any method mentioned here has a custom serialization handler.        static $methods = [            'add_structure' => true,            'add_list'      => true,            'add_blob'      => true,            'add_timestamp' => true,            'add_boolean'   => true,            'add_map'       => true,            'add_string'    => true        ];        $type = 'add_' . $shape['type'];        if (isset($methods[$type])) {            $this->{$type}($shape, $name, $value, $xml);        } else {            $this->defaultShape($shape, $name, $value, $xml);        }    }    private function defaultShape(Shape $shape, $name, $value, XMLWriter $xml)    {        $this->startElement($shape, $name, $xml);        $xml->text($value);        $xml->endElement();    }    private function add_structure(        StructureShape $shape,        $name,        array $value,        \XMLWriter $xml    ) {        $this->startElement($shape, $name, $xml);        foreach ($this->getStructureMembers($shape, $value) as $k => $definition) {            $this->format(                $definition['member'],                $definition['member']['locationName'] ?: $k,                $definition['value'],                $xml            );        }        $xml->endElement();    }    private function getStructureMembers(StructureShape $shape, array $value)    {        $members = [];        foreach ($value as $k => $v) {            if ($v !== null && $shape->hasMember($k)) {                $definition = [                    'member' => $shape->getMember($k),                    'value'  => $v,                ];                if ($definition['member']['xmlAttribute']) {                    // array_unshift_associative                    $members = [$k => $definition] + $members;                } else {                    $members[$k] = $definition;                }            }        }        return $members;    }    private function add_list(        ListShape $shape,        $name,        array $value,        XMLWriter $xml    ) {        $items = $shape->getMember();        if ($shape['flattened']) {            $elementName = $name;        } else {            $this->startElement($shape, $name, $xml);            $elementName = $items['locationName'] ?: 'member';        }        foreach ($value as $v) {            $this->format($items, $elementName, $v, $xml);        }        if (!$shape['flattened']) {            $xml->endElement();        }    }    private function add_map(        MapShape $shape,        $name,        array $value,        XMLWriter $xml    ) {        $xmlEntry = $shape['flattened'] ? $shape['locationName'] : 'entry';        $xmlKey = $shape->getKey()['locationName'] ?: 'key';        $xmlValue = $shape->getValue()['locationName'] ?: 'value';        $this->startElement($shape, $name, $xml);        foreach ($value as $key => $v) {            $this->startElement($shape, $xmlEntry, $xml);            $this->format($shape->getKey(), $xmlKey, $key, $xml);            $this->format($shape->getValue(), $xmlValue, $v, $xml);            $xml->endElement();        }        $xml->endElement();    }    private function add_blob(Shape $shape, $name, $value, XMLWriter $xml)    {        $this->startElement($shape, $name, $xml);        $xml->writeRaw(base64_encode($value));        $xml->endElement();    }    private function add_timestamp(        TimestampShape $shape,        $name,        $value,        XMLWriter $xml    ) {        $this->startElement($shape, $name, $xml);        $timestampFormat = !empty($shape['timestampFormat'])            ? $shape['timestampFormat']            : 'iso8601';        $xml->writeRaw(TimestampShape::format($value, $timestampFormat));        $xml->endElement();    }    private function add_boolean(        Shape $shape,        $name,        $value,        XMLWriter $xml    ) {        $this->startElement($shape, $name, $xml);        $xml->writeRaw($value ? 'true' : 'false');        $xml->endElement();    }    private function add_string(        Shape $shape,        $name,        $value,        XMLWriter $xml    ) {        if ($shape['xmlAttribute']) {            $xml->writeAttribute($shape['locationName'] ?: $name, $value);        } else {            $this->defaultShape($shape, $name, $value, $xml);        }    }}
 |