将字符串列表转换为sml中的三元树

时间:2014-05-07 18:30:46

标签: xml-parsing tree sml smlnj

我想将字符串列表转换为三元树。树应具有以下数据类型

datatype ttree = node of string*ttree list*string|leaf of string*string*string

例如,

["<root>","<a3>","<b2>","Father","</b2>","<b3>","Mother","</b3>","</a3>","<a1>","<ffx>","AAA",...] : string list

应转换为

val test = 
node
("<root>",
 [node
    ("<a3>",
     [leaf ("<b2>","Father","<b2>"),leaf ("<b3>","Mother","<b3>")],
     "<a3>"),
  node
    ("<a1>",[leaf ("<ffx>","AAA","<ffx>"),leaf ("<ff>","BBB","<ff>")],
     "<a1>")],"<root>") : ttree

1 个答案:

答案 0 :(得分:3)

不是最有效的解决方案,但这应该可以解决问题:

datatype ttree = node of string*ttree list*string | leaf of string*string*string

val l = ["<root>",
          "<a3>",
            "<b2>","Father","</b2>",
            "<b3>","Mother","</b3>",
          "</a3>",
          "<a1>",
            "<ffx>","AAA","</ffx>",
          "</a1>"]

(*listToTree(l) = string list to ternary tree*)
fun listToTree(l : string list) : ttree =
  let
    (*isLeaf(s1, s3) = true if s1=<a> and s3=</a>, 
                        a can be replaced with anything
                       false otherwise*)
    fun isLeaf(s1 : string, s3 : string) : bool =
      let
        val (e1, e3) = (explode s1, explode s3)
        val (t1c1::t1) = e1
        val t1e = List.last t1
        val (t3c1::t3c2::t3) = e3
        val t3e = List.last t3
      in
        if t1c1 = #"<" andalso 
           t1c1 = t3c1 andalso 
           t1e = #">"  andalso
           t1e = t3e   andalso
           t3c2 = #"/" andalso
           t1 = t3     then true else false
      end

    (*parseUntil(l, until, acc) = (p, r),
      where p = acc + a part of l until an element x 
                that satisfies isLeaf(until,x)
        and r = elements of list l after x *)
    fun parseUntil(l : string list, until : string, acc : string list)
           : string list * string list =
      case l of
          []    => (rev acc, [])
        | x::xs => if isLeaf(until, x) 
                   then (rev acc, xs) 
                   else parseUntil(xs, until, x::acc)

    (*parseList(l) = the ttree list of the given string list*)
    fun parseList(l : string list) : ttree list =
      case l of
          [] => []
        | x::xs => let
          val (parsed, rest) = parseUntil(xs, x, [])
        in
          if length parsed = 1 
          then leaf(x, hd xs, x)::parseList(rest)
          else node(x, parseList(parsed), x)::parseList(rest)
        end
  in
    hd (parseList l)
  end

val result = listToTree l;

它基本上是这样做的:

  • 获得标记后,获取列表元素,直到关闭标记。

  • 使用元素调用相同的解析器函数,直到close标记,并将结果放在节点的列表中。

  • 使用close标记后面的元素调用相同的解析器函数,并将它们附加到上一级列表。

我希望我能提供帮助。