diff --git a/docs/source/1.0/spec/aws/aws-ec2-query-protocol.rst b/docs/source/1.0/spec/aws/aws-ec2-query-protocol.rst
index 52de2616157..8002f8320fb 100644
--- a/docs/source/1.0/spec/aws/aws-ec2-query-protocol.rst
+++ b/docs/source/1.0/spec/aws/aws-ec2-query-protocol.rst
@@ -23,7 +23,9 @@ Summary
OR in a ``x-form-url-encoded`` body and responses in XML documents. This
protocol is an Amazon EC2-specific extension of the ``awsQuery`` protocol.
Trait selector
- ``service``
+ ``service [trait|xmlNamespace]``
+
+ *Service shapes with the xmlNamespace trait*
Value type
Annotation trait.
diff --git a/docs/source/1.0/spec/aws/aws-query-protocol.rst b/docs/source/1.0/spec/aws/aws-query-protocol.rst
index d2dbe30761c..4689c052d4d 100644
--- a/docs/source/1.0/spec/aws/aws-query-protocol.rst
+++ b/docs/source/1.0/spec/aws/aws-query-protocol.rst
@@ -22,7 +22,9 @@ Summary
Adds support for an HTTP protocol that sends requests in the query
string and responses in XML documents.
Trait selector
- ``service``
+ ``service [trait|xmlNamespace]``
+
+ *Service shapes with the xmlNamespace trait*
Value type
Annotation trait.
See
diff --git a/docs/source/1.0/spec/core/xml-traits.rst b/docs/source/1.0/spec/core/xml-traits.rst
index 1475b7b179f..6c5ce50fc02 100644
--- a/docs/source/1.0/spec/core/xml-traits.rst
+++ b/docs/source/1.0/spec/core/xml-traits.rst
@@ -937,7 +937,9 @@ The XML serialization is:
Summary
Adds an `XML namespace`_ to an XML element.
Trait selector
- ``*``
+ ``:is(service, member, simpleType, collection, map, structure, union)``
+
+ *Service, simple types, list, map, set, structure, or union*
Value type
``structure``
Conflicts with
diff --git a/smithy-aws-protocol-tests/model/awsQuery/main.smithy b/smithy-aws-protocol-tests/model/awsQuery/main.smithy
index 7046a0742fc..0a430261fbe 100644
--- a/smithy-aws-protocol-tests/model/awsQuery/main.smithy
+++ b/smithy-aws-protocol-tests/model/awsQuery/main.smithy
@@ -35,6 +35,7 @@ service AwsQuery {
XmlMapsXmlName,
FlattenedXmlMap,
FlattenedXmlMapWithXmlName,
+ FlattenedXmlMapWithXmlNamespace,
XmlEmptyMaps,
// Output XML list tests
diff --git a/smithy-aws-protocol-tests/model/awsQuery/xml-lists.smithy b/smithy-aws-protocol-tests/model/awsQuery/xml-lists.smithy
index e91e49183d2..970941f6de2 100644
--- a/smithy-aws-protocol-tests/model/awsQuery/xml-lists.smithy
+++ b/smithy-aws-protocol-tests/model/awsQuery/xml-lists.smithy
@@ -79,6 +79,10 @@ apply XmlLists @httpResponseTests([
bye
yep
nope
+ a
+ b
+ a
+ b
-
1
@@ -107,6 +111,8 @@ apply XmlLists @httpResponseTests([
renamedListMembers: ["foo", "bar"],
flattenedList: ["hi", "bye"],
flattenedList2: ["yep", "nope"],
+ flattenedListWithMemberNamespace: ["a", "b"],
+ flattenedListWithNamespace: ["a", "b"],
structureList: [
{
a: "1",
@@ -180,6 +186,17 @@ structure XmlListsOutput {
// serializing flattened lists in structures.
flattenedList2: RenamedListMembers,
+ // The XML namespace of the flattened list's member is used, and
+ // list's XML namespace is disregarded.
+ @xmlFlattened
+ flattenedListWithMemberNamespace: ListWithMemberNamespace,
+
+ // Again, the XML namespace of the flattened list is ignored.
+ // The namespace of the member is used, which is empty, so
+ // no xmlns attribute appears on the serialized XML.
+ @xmlFlattened
+ flattenedListWithNamespace: ListWithNamespace,
+
@xmlName("myStructureList")
structureList: StructureList
}
@@ -201,3 +218,14 @@ structure StructureListMember {
@xmlName("other")
b: String,
}
+
+@xmlNamespace(uri: "https://xml-list.example.com")
+list ListWithMemberNamespace {
+ @xmlNamespace(uri: "https://xml-member.example.com")
+ member: String,
+}
+
+@xmlNamespace(uri: "https://xml-list.example.com")
+list ListWithNamespace {
+ member: String,
+}
diff --git a/smithy-aws-protocol-tests/model/awsQuery/xml-maps.smithy b/smithy-aws-protocol-tests/model/awsQuery/xml-maps.smithy
index 0d3ff2006a6..7c686615d19 100644
--- a/smithy-aws-protocol-tests/model/awsQuery/xml-maps.smithy
+++ b/smithy-aws-protocol-tests/model/awsQuery/xml-maps.smithy
@@ -269,3 +269,57 @@ map FlattenedXmlMapWithXmlNameOutputMap {
@xmlName("V")
value: String,
}
+
+/// Flattened maps with @xmlNamespace and @xmlName
+operation FlattenedXmlMapWithXmlNamespace {
+ output: FlattenedXmlMapWithXmlNamespaceOutput
+}
+
+apply FlattenedXmlMapWithXmlNamespace @httpResponseTests([
+ {
+ id: "QueryQueryFlattenedXmlMapWithXmlNamespace",
+ documentation: "Serializes flattened XML maps in responses that have xmlNamespace and xmlName on members",
+ protocol: awsQuery,
+ code: 200,
+ body: """
+
+
+
+ a
+ A
+
+
+ b
+ B
+
+
+ """,
+ bodyMediaType: "application/xml",
+ headers: {
+ "Content-Type": "text/xml"
+ },
+ params: {
+ myMap: {
+ a: "A",
+ b: "B",
+ }
+ }
+ }
+])
+
+structure FlattenedXmlMapWithXmlNamespaceOutput {
+ @xmlFlattened
+ @xmlName("KVP")
+ @xmlNamespace(uri: "https://the-member.example.com")
+ myMap: FlattenedXmlMapWithXmlNamespaceOutputMap,
+}
+
+map FlattenedXmlMapWithXmlNamespaceOutputMap {
+ @xmlName("K")
+ @xmlNamespace(uri: "https://the-key.example.com")
+ key: String,
+
+ @xmlName("V")
+ @xmlNamespace(uri: "https://the-value.example.com")
+ value: String,
+}
diff --git a/smithy-aws-protocol-tests/model/ec2Query/xml-lists.smithy b/smithy-aws-protocol-tests/model/ec2Query/xml-lists.smithy
index 1ea6f16dfd8..0e9beab5e94 100644
--- a/smithy-aws-protocol-tests/model/ec2Query/xml-lists.smithy
+++ b/smithy-aws-protocol-tests/model/ec2Query/xml-lists.smithy
@@ -23,7 +23,8 @@ use smithy.test#httpResponseTests
/// 4. XML lists with @xmlName on its members
/// 5. Flattened XML lists.
/// 6. Flattened XML lists with @xmlName.
-/// 7. Lists of structures.
+/// 7. Flattened XML lists with @xmlNamespace.
+/// 8. Lists of structures.
operation XmlLists {
output: XmlListsOutput
}
@@ -78,6 +79,10 @@ apply XmlLists @httpResponseTests([
bye
yep
nope
+ a
+ b
+ a
+ b
-
1
@@ -106,6 +111,8 @@ apply XmlLists @httpResponseTests([
renamedListMembers: ["foo", "bar"],
flattenedList: ["hi", "bye"],
flattenedList2: ["yep", "nope"],
+ flattenedListWithMemberNamespace: ["a", "b"],
+ flattenedListWithNamespace: ["a", "b"],
structureList: [
{
a: "1",
@@ -177,6 +184,17 @@ structure XmlListsOutput {
// serializing flattened lists in structures.
flattenedList2: RenamedListMembers,
+ // The XML namespace of the flattened list's member is used, and
+ // list's XML namespace is disregarded.
+ @xmlFlattened
+ flattenedListWithMemberNamespace: ListWithMemberNamespace,
+
+ // Again, the XML namespace of the flattened list is ignored.
+ // The namespace of the member is used, which is empty, so
+ // no xmlns attribute appears on the serialized XML.
+ @xmlFlattened
+ flattenedListWithNamespace: ListWithNamespace,
+
@xmlName("myStructureList")
structureList: StructureList
}
@@ -198,3 +216,14 @@ structure StructureListMember {
@xmlName("other")
b: String,
}
+
+@xmlNamespace(uri: "https://xml-list.example.com")
+list ListWithMemberNamespace {
+ @xmlNamespace(uri: "https://xml-member.example.com")
+ member: String,
+}
+
+@xmlNamespace(uri: "https://xml-list.example.com")
+list ListWithNamespace {
+ member: String,
+}
diff --git a/smithy-aws-protocol-tests/model/restXml/document-lists.smithy b/smithy-aws-protocol-tests/model/restXml/document-lists.smithy
index 7743210874d..288cf4c4eb3 100644
--- a/smithy-aws-protocol-tests/model/restXml/document-lists.smithy
+++ b/smithy-aws-protocol-tests/model/restXml/document-lists.smithy
@@ -26,7 +26,8 @@ use smithy.test#httpResponseTests
/// 4. XML lists with @xmlName on its members
/// 5. Flattened XML lists.
/// 6. Flattened XML lists with @xmlName.
-/// 7. Lists of structures.
+/// 7. Flattened XML lists with @xmlNamespace.
+/// 8. Lists of structures.
@idempotent
@http(uri: "/XmlLists", method: "PUT")
operation XmlLists {
@@ -176,6 +177,10 @@ apply XmlLists @httpResponseTests([
bye
yep
nope
+ a
+ b
+ a
+ b
-
1
@@ -203,6 +208,8 @@ apply XmlLists @httpResponseTests([
renamedListMembers: ["foo", "bar"],
flattenedList: ["hi", "bye"],
flattenedList2: ["yep", "nope"],
+ flattenedListWithMemberNamespace: ["a", "b"],
+ flattenedListWithNamespace: ["a", "b"],
structureList: [
{
a: "1",
@@ -300,6 +307,17 @@ structure XmlListsInputOutput {
// serializing flattened lists in structures.
flattenedList2: RenamedListMembers,
+ // The XML namespace of the flattened list's member is used, and
+ // list's XML namespace is disregarded.
+ @xmlFlattened
+ flattenedListWithMemberNamespace: ListWithMemberNamespace,
+
+ // Again, the XML namespace of the flattened list is ignored.
+ // The namespace of the member is used, which is empty, so
+ // no xmlns attribute appears on the serialized XML.
+ @xmlFlattened
+ flattenedListWithNamespace: ListWithNamespace,
+
@xmlName("myStructureList")
structureList: StructureList
}
@@ -321,3 +339,14 @@ structure StructureListMember {
@xmlName("other")
b: String,
}
+
+@xmlNamespace(uri: "https://xml-list.example.com")
+list ListWithMemberNamespace {
+ @xmlNamespace(uri: "https://xml-member.example.com")
+ member: String,
+}
+
+@xmlNamespace(uri: "https://xml-list.example.com")
+list ListWithNamespace {
+ member: String,
+}
diff --git a/smithy-aws-protocol-tests/model/restXml/document-maps.smithy b/smithy-aws-protocol-tests/model/restXml/document-maps.smithy
index d6c240f1e0e..ec078390a65 100644
--- a/smithy-aws-protocol-tests/model/restXml/document-maps.smithy
+++ b/smithy-aws-protocol-tests/model/restXml/document-maps.smithy
@@ -433,3 +433,56 @@ map FlattenedXmlMapWithXmlNameInputOutputMap {
@xmlName("V")
value: String,
}
+
+/// Flattened maps with @xmlNamespace and @xmlName
+@http(uri: "/FlattenedXmlMapWithXmlNamespace", method: "POST")
+operation FlattenedXmlMapWithXmlNamespace {
+ output: FlattenedXmlMapWithXmlNamespaceOutput
+}
+
+apply FlattenedXmlMapWithXmlNamespace @httpResponseTests([
+ {
+ id: "RestXmlFlattenedXmlMapWithXmlNamespace",
+ documentation: "Serializes flattened XML maps in responses that have xmlNamespace and xmlName on members",
+ protocol: restXml,
+ code: 200,
+ body: """
+
+
+ a
+ A
+
+
+ b
+ B
+
+ """,
+ bodyMediaType: "application/xml",
+ headers: {
+ "Content-Type": "application/xml"
+ },
+ params: {
+ myMap: {
+ a: "A",
+ b: "B",
+ }
+ }
+ }
+])
+
+structure FlattenedXmlMapWithXmlNamespaceOutput {
+ @xmlFlattened
+ @xmlName("KVP")
+ @xmlNamespace(uri: "https://the-member.example.com")
+ myMap: FlattenedXmlMapWithXmlNamespaceOutputMap,
+}
+
+map FlattenedXmlMapWithXmlNamespaceOutputMap {
+ @xmlName("K")
+ @xmlNamespace(uri: "https://the-key.example.com")
+ key: String,
+
+ @xmlName("V")
+ @xmlNamespace(uri: "https://the-value.example.com")
+ value: String,
+}
diff --git a/smithy-aws-protocol-tests/model/restXml/main.smithy b/smithy-aws-protocol-tests/model/restXml/main.smithy
index 51ec85e57b1..1829415ce69 100644
--- a/smithy-aws-protocol-tests/model/restXml/main.smithy
+++ b/smithy-aws-protocol-tests/model/restXml/main.smithy
@@ -71,6 +71,7 @@ service RestXml {
XmlMapsXmlName,
FlattenedXmlMap,
FlattenedXmlMapWithXmlName,
+ FlattenedXmlMapWithXmlNamespace,
// @xmlAttribute tests
XmlAttributes,
diff --git a/smithy-aws-protocol-tests/model/restXmlWithNamespace/main.smithy b/smithy-aws-protocol-tests/model/restXmlWithNamespace/main.smithy
new file mode 100644
index 00000000000..0cb5c062bcd
--- /dev/null
+++ b/smithy-aws-protocol-tests/model/restXmlWithNamespace/main.smithy
@@ -0,0 +1,131 @@
+$version: "1.0"
+
+namespace aws.protocoltests.restxml.xmlns
+
+use aws.api#service
+use aws.protocols#restXml
+use smithy.test#httpRequestTests
+use smithy.test#httpResponseTests
+
+/// A REST XML service that sends XML requests and responses.
+///
+/// This service and test case is complementary to the test cases
+/// in the `restXml` directory, but the service under test here has
+/// the `xmlNamespace` trait applied to it.
+///
+/// See https://github.com/awslabs/smithy/issues/616
+@service(sdkId: "Rest Xml Protocol Namespace")
+@xmlNamespace(uri: "https://example.com")
+@restXml
+service RestXmlWithNamespace {
+ version: "2019-12-16",
+ operations: [SimpleScalarProperties]
+}
+
+// This example serializes simple scalar types in the top level XML document.
+// Note that headers are not serialized in the payload.
+//
+// This is a partial copy of aws.protocoltests.restxml#SimpleScalarProperties,
+// but only includes enough test cases to ensure a namespace is serialized.
+@idempotent
+@http(uri: "/SimpleScalarProperties", method: "PUT")
+operation SimpleScalarProperties {
+ input: SimpleScalarPropertiesInputOutput,
+ output: SimpleScalarPropertiesInputOutput
+}
+
+apply SimpleScalarProperties @httpRequestTests([
+ {
+ id: "XmlNamespaceSimpleScalarProperties",
+ documentation: "Serializes simple scalar properties",
+ protocol: restXml,
+ method: "PUT",
+ uri: "/SimpleScalarProperties",
+ body: """
+
+ string
+ true
+ false
+ 1
+ 2
+ 3
+ 4
+ 5.5
+ 6.5
+
+ """,
+ bodyMediaType: "application/xml",
+ headers: {
+ "Content-Type": "application/xml",
+ "X-Foo": "Foo",
+ },
+ params: {
+ foo: "Foo",
+ stringValue: "string",
+ trueBooleanValue: true,
+ falseBooleanValue: false,
+ byteValue: 1,
+ shortValue: 2,
+ integerValue: 3,
+ longValue: 4,
+ floatValue: 5.5,
+ doubleValue: 6.5,
+ }
+ }
+])
+
+apply SimpleScalarProperties @httpResponseTests([
+ {
+ id: "XmlNamespaceSimpleScalarProperties",
+ documentation: "Serializes simple scalar properties",
+ protocol: restXml,
+ code: 200,
+ body: """
+
+ string
+ true
+ false
+ 1
+ 2
+ 3
+ 4
+ 5.5
+ 6.5
+
+ """,
+ bodyMediaType: "application/xml",
+ headers: {
+ "Content-Type": "application/xml",
+ "X-Foo": "Foo",
+ },
+ params: {
+ foo: "Foo",
+ stringValue: "string",
+ trueBooleanValue: true,
+ falseBooleanValue: false,
+ byteValue: 1,
+ shortValue: 2,
+ integerValue: 3,
+ longValue: 4,
+ floatValue: 5.5,
+ doubleValue: 6.5,
+ }
+ }
+])
+
+structure SimpleScalarPropertiesInputOutput {
+ @httpHeader("X-Foo")
+ foo: String,
+
+ stringValue: String,
+ trueBooleanValue: Boolean,
+ falseBooleanValue: Boolean,
+ byteValue: Byte,
+ shortValue: Short,
+ integerValue: Integer,
+ longValue: Long,
+ floatValue: Float,
+
+ @xmlName("DoubleDribble")
+ doubleValue: Double,
+}
diff --git a/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.json b/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.json
index 9669251129d..0a1506679cf 100644
--- a/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.json
+++ b/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.json
@@ -124,7 +124,7 @@
"type": "structure",
"traits": {
"smithy.api#trait": {
- "selector": "service"
+ "selector": "service [trait|xmlNamespace]"
},
"smithy.api#protocolDefinition": {
"noInlineDocumentSupport": true,
@@ -143,7 +143,7 @@
"type": "structure",
"traits": {
"smithy.api#trait": {
- "selector": "service"
+ "selector": "service [trait|xmlNamespace]"
},
"smithy.api#protocolDefinition": {
"noInlineDocumentSupport": true,
diff --git a/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/xml-protocols-do-not-support-documents.smithy b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/xml-protocols-do-not-support-documents.smithy
index 2852cba7e2e..3d1b24ad37f 100644
--- a/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/xml-protocols-do-not-support-documents.smithy
+++ b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/xml-protocols-do-not-support-documents.smithy
@@ -7,6 +7,7 @@ use aws.protocols#awsQuery
@awsQuery
@suppress(["DeprecatedTrait"]) // ignore the fact that the awsQuery trait is deprecated
+@xmlNamespace(uri: "https://example.com")
service InvalidExample {
version: "2020-06-15",
operations: [Operation1]
diff --git a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy
index b48215dec1e..66182540152 100644
--- a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy
+++ b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy
@@ -299,7 +299,8 @@ structure xmlFlattened {}
string xmlName
/// Adds an xmlns namespace definition URI to an XML element.
-@trait(conflicts: [xmlAttribute])
+@trait(selector: ":is(service, member, simpleType, collection, map, structure, union)",
+ conflicts: [xmlAttribute])
@tags(["diff.error.const"])
structure xmlNamespace {
/// The namespace URI for scoping this XML element.