Serialization to XML

My task is to create a small XML file using OCaml.

I have tried several libraries:

  • csvfields+ppx_xml_conv: version 0.16.0 still cannot serialize types with any name but t (probably due to a bug similar to that fixed in ppx_csv_convv0.15~preview.124.06+323 · janestreet/ppx_csv_conv@7ab2b7d · GitHub);
  • ppx_protocol_conv — works, but the list is always serialized to l tag and the record is always serialized to record; I can change names only for record fields;
  • ezxmlm — I failed to find how to make a tag with a custom namespace;
  • xmlm — too complicated for my simple task.

It cannot be this hard, I must be doing something wrong.

What is the standard way to create simple XML data?

Can you specify a sample data type that looks like the type you want to encode, and how you want the fields to be encoded? Since there are different valid ways of encoding eg a record type to XML, like

type person = { id : int; name : string }

Could be encoded as

<person>
  <id>1</id>
  <name>Bob</name>
</person>

Or as

<person id="1" name="Bob"/>

EDIT: let me also mention that my library pure-html allows creating and rendering XML data. Eg for the above type, I could encode it both ways shown:

open Pure_html

let encoding1 =
  let person = std_tag "person"
  and id = std_tag "id"
  and name = std_tag "name" in
  fun { id = i; name = n } ->
    person [] [
      id [] [txt "%d" i];
      name [] [txt "%s" n];
    ]

let encoding2 =
  let person = std_tag "person"
  and id = int_attr "id"
  and name = string_attr "name" in
  fun { id = i; name = n } ->
    person [id i; name "%s" n] []

And then you would use Pure_html (pure-html.Pure_html) to render these values as strings:

let str1 = to_xml (encoding1 { id = 1; name = "Bob" })
let str2 = to_xml (encoding2 { id = 1; name = "Bob" })
1 Like

Can you specify a sample data type that looks like the type you want to encode, and how you want the fields to be encoded?

I want to encode a type looking like this:

  type answer =
    { resource : string
    ; state : string
    }
  
  type t = answer list

to the XML like

<myns:answers>
 <myns:answer>
  <myns:resource>Resource 1</myns:resource>
  <myns:state>Available</myns:state>
 </myns:answer>
 <myns:answer>
  <myns:resource>Resource 2</myns:resource>
  <myns:state>Unavailable</myns:state>
 </myns:answer>
</myns:answers>

let me also mention that my library pure-html allows creating and rendering XML data

Thank you for mentioning pure-html, I’ll take a look!

1 Like

No prob. Just to clarify, you can easily use namespaces: let answers = std_tag "myns:answers". And you can also easily wrap the answers in the myns:answers tag, eg:

module Myns = struct
  let answers = std_tag "myns:answers"
  let answer = ...
  ...
end

let answer_node { resource; state } =
  Myns.answer [] [
    Myns.resource "%s" resource;
    Myns.state "%s" state;
  ]

let answers_node answers =
  Myns.answers [] (List.map answer_node answers)
1 Like

Thank you so much! So, your library is indeed the solution.

I didn’t find a way to generate an XML prolog:

     <?xml version="1.0" encoding="utf-8" ?>

but it of course could (and probably will) be added manually in my code.

Great library with a very clean interface BTW.

Thanks! I’ll add an optional parameter to print the prologue in the next release. Good catch.

2 Likes