As per the XML Specification, a compliant parser must transform all whitespace characters to space (0x20) on parsing. This means that if one wants to preserve the spacing, the value should be encoded. Ox does not do the encoding. Therefore:
el = Ox::Element.new('element')
el["attr"] = "I have\nnewlines"
puts Ox.dump(el)
#
# <element attr="I have
# newlines"/>
And a compliant parser should discard the \n there and interpret it as . This means that by default Ox does not roundtrip.
Ox should do something like value.gsub(/([^[:ascii:]]|[\s&&[^ ]])/){|i| "&##{i.ord};" } on attribute values