格式模块中的框和 XML

Boxes and XML in Format module

我想在 Format module 中使用框和 XML 打印输出。 创意格式如下:

<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>

目前我的代码如下,它没有完全按照我的预期打印(我省略了不正确的结果)。

  (* 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

我不确定我是否理解这个框,尤其是当涉及 XML 时。有谁知道如何正确编写这些格式?

Format在打印带缩进的数据时很有用,但它的缩进算法有点棘手,很难完美模拟其他缩进策略。也许自己处理缩进级别更容易。

这样的怎么样?

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

这是上面测试用例的输出:

<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>

通过调整格式字符串 @[<hv 3><%s>@,%a@;<0 -3></%s>@],您可以强制其水平或垂直布局。要获得您指定的确切格式,您需要默认标签框是垂直的 <v 3>,但特殊情况下您的 name 标签框是水平的 <h>。但是,我决定提供一个更通用的示例。

让我解释一下。 @[<hv 3> 打开一个框,它可以在水平 h 和垂直 v 布局之间交替,具体取决于框的内容是否适合一行,在我们的例子中是 50 个字符(请参阅Format.set_margin 50)。 @[<hv 3>中的3是缩进级别。 <%s> 是开始的 XML 标签,</%s>——结束。开始标记在框内,但没有缩进,因为缩进仅在像 @, 这样的中断提示上引入。我们希望结束标记缩进 而不是 ,这就是为什么我们引入了一个中断提示 @;<0 -3>,它在垂直布局的情况下取消缩进 -3,但引入了 0 横向空格。请注意,我正在使用的 Format.pp_print_list 在列表元素之间引入了中断提示 @,(默认情况下)。

希望这有用。如果您有任何问题,请告诉我。

您使用方框处理缩进。要实现此缩进,您需要使用如下框(括号划定框):

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

请注意框和标签的嵌套方式不同Gasoline中使用了此技术,请参阅:

请注意,来自 Gasolineauthorkit 对于编写简单的临时 SGML 很有用文件,但在高级案例中,来自 ocsigen 项目的库可能更有用(但更难使用)。