open Markup type element = { namespace : string; local_name : string; attributes : (string * string) list; children : (element, string) Either.t list; } let tree s : element option = let element (namespace, name) attributes children = Either.Left { namespace; local_name=name; attributes=List.filter_map (fun ((ns, name), content) -> (* remove xmlns -- we don't need it. *) match ns with | "http://www.w3.org/2000/xmlns/" -> None | _ -> Some (name, content)) attributes; children; } and text ss = Either.Right (String.concat "" ss) in let opt_el = tree ~text ~element s in Option.bind opt_el (Either.fold ~left:Option.some ~right:(fun _ -> None))