kgiszczak / shale

Shale is a Ruby object mapper and serializer for JSON, YAML, TOML, CSV and XML. It allows you to parse JSON, YAML, TOML, CSV and XML data and convert it into Ruby data structures, as well as serialize data structures into JSON, YAML, TOML, CSV or XML.
https://shalerb.org/
MIT License
618 stars 19 forks source link

XML tag without content #13

Closed martinnicolas closed 1 year ago

martinnicolas commented 1 year ago

Some times we need to define an xml tag without content inside like this:

  <Tag> </Tag>

Currently, shale is closing xml tags without content like this:

  <Tag/>

Im fixing this mapping content to empty string. Like this

  attribute :content, Shale::Type::String, default: -> { " " }

and this

  xml do
    root 'Tag'
    map_content to: :content

It could be a nice improvement to provide an option to choose how to close tags without content!.

kgiszczak commented 1 year ago

Yeah, that would be a nice addition, unfortunately that's not something Shale controls. How the rendering is done is entirely dependent on the underlaying XML parser, or event parser version/architecture (e.g. I ran into issues where generated XML was different on Mac OS and Linux when using Nokogiri).

You can try to use different parser, e.g. REXML and Ox allow to control how the nodes are rendered by using nil or empty string '' e.g.

require 'shale'
require 'shale/adapter/rexml'

Shale.xml_adapter = Shale::Adapter::REXML

class Person < Shale::Mapper
  attribute :first_name, Shale::Type::String
  attribute :last_name, Shale::Type::String

  xml do
    root 'person'
    map_element 'first_name', to: :first_name, render_nil: true
    map_element 'last_name', to: :last_name, render_nil: true
  end
end

person = Person.new(first_name: '', last_name: nil)

puts person.to_xml(pretty: true)

This will render:

<person>
  <first_name></first_name>
  <last_name/>
</person>
martinnicolas commented 1 year ago

Nice!. I will try these alternatives. Thanks!.