Boxes and XML in Format module

只愿长相守 提交于 2019-12-25 01:15:44

问题


I would like to print an output using boxes and XML in Format module. An idea format is as follows:

<Events>
   <Event>
      <name> haha </name>
      <name> haha </name>
   </Event>
   <Event>
      <name> lili </name>
      <name> lili </name>
   </Event>
   <Event>
      <name> lolo </name>
      <name> lolo </name>
   </Event>
</Events>

At the moment my code is as follows, it does not print exactly what I expect (I omit to put the incorrect result here).

  (* in event.ml *)
  let print_name (fmt: formatter) (x: t) : unit =
    Format.open_tag "Name";
    Format.fprintf fmt "%s" (get_name x);
    Format.close_tag ()

  (* in events.ml *)
  let print (fmt: formatter) (x: t) : unit =
    let print (fmt: formatter) (x: t) : unit =
      List.iter
      (fun m ->
         Format.open_tag "Event";
         Format.fprintf fmt "@,@[<v 4>%a@,%a@," Event.print_name m 
                                     Event.print_name m; (* print twice *)
         Format.close_tag ();
         Format.fprintf fmt "@,@]")
      x
    in
    Format.open_tag "Events";
    Format.fprintf fmt "@,@[<v 4>%a@]@," print x;
    Format.close_tag ()

    (* in main.ml *)
    Format.fprintf Format.std_formatter "%a" Events.print x

I am not sure I understand well the box, especially when XML is involved. Does anyone know how to write these formats correctly?


回答1:


Format is useful to print data with indentation, but its indentation algorithm is a bit tricky and is hard to simulate other indentation policies perfectly. Maybe it is easier to handle indentation levels by yourself.




回答2:


How about something like this?

let format, format_list = Format.(fprintf, pp_print_list) (* sorry, hate these cryptic names *)

type xml =
  | Tag of string * xml list
  | String of string

let rec format_xml f = function
  | Tag (name, body) ->
      let format_body = format_list format_xml in
      format f "@[<hv 3><%s>@,%a@;<0 -3></%s>@]" name format_body body name
  | String text -> format f "%s" text

let tag name body = Tag (name, body)
let name s = tag "name" [String s]

let () =
  Format.set_margin 50;

  let xml = tag "Events" [
    tag "Event" [
      name "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; name "b"; name "c";
    ];
    tag "Event" [name "a"; name "b"; name "c"];
    tag "Event" [name "a"; name "b"];
    tag "Event" [];
  ] in
  format_xml Format.std_formatter xml

Here's the output of the test-case above:

<Events>
   <Event>
      <name>
         aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      </name>
      <name>b</name>
      <name>c</name>
   </Event>
   <Event>
      <name>a</name>
      <name>b</name>
      <name>c</name>
   </Event>
   <Event><name>a</name><name>b</name></Event>
   <Event></Event>
</Events>

By tweaking the format string @[<hv 3><%s>@,%a@;<0 -3></%s>@], you can either force it to lay out horizontally or vertically. To get the exact formatting that you specified, you would need the default tag box to be vertical <v 3>, but special-case your name tag box to be horizontal <h>. However, I decided to provide a more general example.

Let me explain. @[<hv 3> opens a box, which can alternate between horizontal h and vertical v layouts, depending on whether the contents of the box fit a single line, which in our case is 50 characters (see Format.set_margin 50). 3 in @[<hv 3> is the indentation level. <%s> is the opening XML tag, </%s>—closing. The opening tag is inside the box, but it is not indented, because indentation is introduced only on break hints like @,. We want the closing tag to not be indented, that's why we introduce a break hint @;<0 -3> which un-indents -3 in case of vertical layout, but introduces 0 spaces in horizontal. Note that Format.pp_print_list which I'm using introduces break hints @, between list elements (by default).

Hope this is useful. Let me know if you have questions.




回答3:


You handle indentation using boxes. To realize this indentation you need to use boxes as follows (parens delineate boxes):

((<tag>contents)</tag>)

Note how boxes and tags are differently nested. This technique is used in Gasoline see:

  • testsuite for usage examples
  • implementation

Note that the authorkit from Gasoline is useful for writing simple ad-hoc SGML files but in advanced caes, libraries from the ocsigen projects are probably more useful (but harder to use).



来源:https://stackoverflow.com/questions/36489419/boxes-and-xml-in-format-module

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!