From bfa10893fe2b4e96e84086a0b5ddf123abc56112 Mon Sep 17 00:00:00 2001 From: Yenfry Herrera Feliz Date: Tue, 6 Jan 2026 11:16:40 -0800 Subject: [PATCH 1/2] fix: location name on structure members When a structure member has the locationName `xmlName trait` then we should use that name instead of the original name. --- src/Api/Serializer/XmlBody.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Api/Serializer/XmlBody.php b/src/Api/Serializer/XmlBody.php index 9ce967e2e1..89bdfd9ff0 100644 --- a/src/Api/Serializer/XmlBody.php +++ b/src/Api/Serializer/XmlBody.php @@ -99,10 +99,7 @@ private function add_structure( // Default to member name $elementName = $k; - // Only use locationName for non-structure members - if (!($definition['member'] instanceof StructureShape) - && $definition['member']['locationName'] - ) { + if ($definition['member']['locationName']) { $elementName = $definition['member']['locationName']; } From 8f3aeffc0e20a2b28af2cacee393c992b74524b6 Mon Sep 17 00:00:00 2001 From: Yenfry Herrera Feliz Date: Tue, 6 Jan 2026 15:55:13 -0800 Subject: [PATCH 2/2] chore: property to identify xmlName level Add a property to know whether the `locationName` was defined at the structure level or at the member level in the model definition. This is needed to decide when we need to use the locationName at the serialization process. --- src/Api/Serializer/RestXmlSerializer.php | 2 +- src/Api/Serializer/XmlBody.php | 3 +- src/Api/ShapeMap.php | 9 ++- .../test_cases/protocols/input/rest-xml.json | 78 +++++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/Api/Serializer/RestXmlSerializer.php b/src/Api/Serializer/RestXmlSerializer.php index 16d8ae7b96..2cf496a4b9 100644 --- a/src/Api/Serializer/RestXmlSerializer.php +++ b/src/Api/Serializer/RestXmlSerializer.php @@ -41,7 +41,7 @@ protected function payload(StructureShape $member, array $value, array &$opts) */ private function getXmlBody(StructureShape $member, array $value) { - $xmlBody = (string)$this->xmlBody->build($member, $value); + $xmlBody = $this->xmlBody->build($member, $value); $xmlBody = str_replace("'", "'", $xmlBody); $xmlBody = str_replace('\r', " ", $xmlBody); $xmlBody = str_replace('\n', " ", $xmlBody); diff --git a/src/Api/Serializer/XmlBody.php b/src/Api/Serializer/XmlBody.php index 89bdfd9ff0..28393bbf2b 100644 --- a/src/Api/Serializer/XmlBody.php +++ b/src/Api/Serializer/XmlBody.php @@ -99,7 +99,8 @@ private function add_structure( // Default to member name $elementName = $k; - if ($definition['member']['locationName']) { + if ($definition['member']['locationName'] + && !isset($definition['member']['locationNameAtStructureLevel'])) { $elementName = $definition['member']['locationName']; } diff --git a/src/Api/ShapeMap.php b/src/Api/ShapeMap.php index 269b2d3a06..1593c2e321 100644 --- a/src/Api/ShapeMap.php +++ b/src/Api/ShapeMap.php @@ -51,7 +51,14 @@ public function resolve(array $shapeRef) return $this->simple[$shape]; } - $definition = $shapeRef + $this->definitions[$shape]; + $shapeDefinition = $this->definitions[$shape]; + $definition = $shapeRef + $shapeDefinition; + // Property to know whether the locationName was set at member level + // or the structure level. + if (isset($shapeDefinition['locationName'])) { + $definition['locationNameAtStructureLevel'] = true; + } + $definition['name'] = $definition['shape']; if (isset($definition['shape'])) { unset($definition['shape']); diff --git a/tests/Api/test_cases/protocols/input/rest-xml.json b/tests/Api/test_cases/protocols/input/rest-xml.json index d0e8ed577a..6295fd7411 100644 --- a/tests/Api/test_cases/protocols/input/rest-xml.json +++ b/tests/Api/test_cases/protocols/input/rest-xml.json @@ -541,6 +541,84 @@ } ] }, + { + "description": "Test cases for xmlName at member level operation", + "metadata": { + "apiVersion": "2019-12-16", + "auth": [ + "aws.auth#sigv4" + ], + "endpointPrefix": "restxml", + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "serviceFullName": "RestXml", + "serviceId": "Rest Xml Protocol", + "signatureVersion": "v4", + "signingName": "RestXml", + "uid": "rest-xml-protocol-2019-12-16" + }, + "shapes": { + "MyShapeInputAndOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "Payload", + "locationName": "CustomPayload" + } + }, + "locationName": "MyShape" + }, + "Payload": { + "type": "structure", + "members": { + "name": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XMLNameAtMemberLevel", + "given": { + "name": "XMLNameAtMemberLevel", + "http": { + "method": "PUT", + "requestUri": "/XMLNameAtMemberLevel", + "responseCode": 200 + }, + "input": { + "shape": "MyShapeInputAndOutput", + "locationName": "XMLNameAtMemberLevelRequest" + }, + "documentation": "

The following example serializes a body that uses an XML name, changing the wrapper name.

", + "idempotent": true + }, + "description": "Serializes a payload using a wrapper name based on the xmlName", + "params": { + "nested": { + "name": "TestParameterValue" + } + }, + "serialized": { + "method": "PUT", + "uri": "/XMLNameAtMemberLevel", + "body": "TestParameterValue", + "headers": { + "Content-Type": "application/xml" + }, + "requireHeaders": [ + "Content-Length" + ] + } + } + ] + }, { "description": "Test cases for ConstantAndVariableQueryString operation", "metadata": {