格式模块中的框和XML

时间:2016-04-08 00:16:16

标签: xml ocaml

我想在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时。有谁知道如何正确编写这些格式?

3 个答案:

答案 0 :(得分:0)

格式对于使用缩进打印数据很有用,但其缩进算法有点棘手,很难完美地模拟其他缩进策略。也许你自己更容易处理缩进级别。

答案 1 :(得分:0)

这样的事情怎么样?

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)。 3中的@[<hv 3>是缩进级别。 <%s>是开始的XML标记</%s> - 关闭。开始标记位于框内,但不缩进,因为缩进仅在@,等中断提示时引入。我们希望 not 的结束标记是缩进的,这就是为什么我们引入了一个中断提示@;<0 -3>,在垂直布局的情况下取消缩进-3,但是引入了{{1}水平空格。请注意,我正在使用的0在列表元素之间引入了提示Format.pp_print_list(默认情况下)。

希望这很有用。如果您有疑问,请告诉我。

答案 2 :(得分:0)

您使用框处理缩进。要实现此缩进,您需要使用如下框(parens描绘框)​​:

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

请注意框和标签以何种方式嵌套。此技术用于 Gasoline ,请参阅:

请注意, Gasoline 中的 authorkit 对于编写简单的ad-hoc SGML 文件非常有用,但在高级版本中,来自 ocsigen 项目可能更有用(但更难使用)。