Skip to content

XML Binding Traits

Juli Tera edited this page Apr 19, 2024 · 5 revisions

This wiki contains a mapping between Smithy XML binding traits and generated Ruby code.

To support these traits, an XML node and parser abstraction is provided in Hearth.

xmlAttribute trait

Serializes an object property as an XML attribute rather than a nested XML element. XML nodes are given an attributes hash to apply to when serializing.

structure MyStructure {
    @xmlAttribute
    foo: String,

    bar: String,
}

The generated code is:

# builders.rb
class MyStructure
  def self.build(node_name, input:)
    xml = Hearth::XML::Node.new(node_name)
    xml.attributes['foo'] = input[:foo] unless input[:foo].nil?
    xml << Hearth::XML::Node.new('bar', input[:bar].to_s) unless input[:bar].nil?
    xml
  end
end

# parsers.rb
class MyStructure
  def self.parse(xml)
    data = Types::MyStructure.new
    data.foo = xml.attributes['foo']
    xml.at('bar') do |node|
      data.bar = (node.text || '')
    end
    return data
  end
end

See Smithy Documentation for more details.

xmlFlattened trait

Unwraps the values of a list or map into the containing structure. For the list or map to be flat, the XML nodes are built and added to the top level node instead of under a nested node.

structure Foo {
    @xmlFlattened
    flat: MyList,

    nested: MyList,
}

list MyList {
    member: String,
}

The generated code is:

# builders.rb
class Foo
  def self.build(node_name, input)
    xml = Hearth::XML::Node.new(node_name)
    xml << MyList.build('flat', input[:my_list]) unless input[:my_list].nil?
    xml << Hearth::XML::Node.new('nested', MyList.build('member', input[:my_list])) unless input[:my_list].nil?
    xml
  end
end

class MyList
  def self.build(node_name, input)
    xml = []
    list.each do |element|
      xml << Hearth::XML::Node.new(node_name, element.to_s) unless element.nil?
    end
    xml
  end
end

# parsers.rb
class Foo
  def self.parse(xml)
    data = Types::Foo.new
    xml.children('flat') do |children|
      data.flat = MyList.parse(children)
    end
    xml.at('nested') do |node|
      children = node.children('member')
      data.nested = MyList.parse(children)
    end
    return data
  end
end

class MyList
  def self.parse(xml)
    data = []
    xml.each do |node|
      data << (node.text || '')
    end
    data
  end
end

See Smithy Documentation for more details.

xmlName trait

Changes the serialized element or attribute name of a structure, union, or member. When using this trait, the node's name is changed.

structure MyStructure {
    @xmlName("Foo")
    foo: String,

    bar: String,
}

The generated code is:

# builders.rb
class MyStructure
  def self.build(node_name, input)
    xml = Hearth::XML::Node.new(node_name)
    xml << Hearth::XML::Node.new('Foo', input[:foo]) unless input[:foo].nil?
    xml << Hearth::XML::Node.new('bar', input[:bar]) unless input[:bar].nil?
    xml
  end
end

# parsers.rb
class MyStructure
  def self.parse(xml)
    data = Types::MyStructure.new
    xml.at('Foo') do |node|
      data.foo = (node.text || '')
    end
    xml.at('bar') do |node|
      data.bar = (node.text || '')
    end
    return data
  end
end

See Smithy Documentation for more details.

xmlNamespace trait

Adds an XML namespace to an XML element. This trait supports a uri and prefix property. This trait is treated similarly to the xmlAttribute trait, using a key of xmlns:{prefix} and a value of uri.

@xmlNamespace(uri: "http://foo.com")
structure MyStructure {
    foo: String,
    bar: String,
}

The generated code is:

# builders.rb
class MyStructure
  def self.build(node_name, input)
    xml = Hearth::XML::Node.new(node_name)
    xml.attributes['xmlns'] = 'http://foo.com'
    xml << Hearth::XML::Node.new('foo', input[:foo]) unless input[:foo].nil?
    xml << Hearth::XML::Node.new('bar', input[:bar]) unless input[:bar].nil?
    xml
  end
end

See Smithy Documentation for more details.