anchor.diff:  -export([parse/1]).
   -export([to_list/1, to_binary/1, to_iolist/1,
            to_pretty_iolist/1, to_pretty_iolist/3]).
  +-export([to_list/2, to_binary/2, to_iolist/2,
  +         to_pretty_iolist/2, to_pretty_iolist/4]).
   -export([escape_attr/1, unescape_attr/1,
            escape_cdata/1, unescape_cdata/1, unescape_cdata_as/2]).
   -on_load(load/0).
  
positive.code: to_list(Element) ->
      binary_to_list(to_binary(Element)).
  
  -spec to_binary(#xmlstreamstart{} | #xmlstreamend{}
                  | xmlterm() | [xmlterm()]) -> binary().
  to_binary(Element) ->
      list_to_binary(to_iolist(Element)).
  
  -spec to_iolist(#xmlstreamstart{} | #xmlstreamend{}
                  | xmlterm() | [xmlterm()]) -> iolist().
  to_iolist(Elements) when is_list(Elements) ->
      lists:map(fun to_iolist/1, Elements);
  to_iolist(#xmlel{name = Name, attrs = Attrs, children = []}) ->
      ["<", Name, attrs_to_iolist(Attrs, []), "/>"];
  to_iolist(#xmlel{name = Name, attrs = Attrs, children = Children}) ->
      ["<", Name, attrs_to_iolist(Attrs, []), ">",
       to_iolist(Children),
       "</", Name, ">"];
  to_iolist(#xmlstreamstart{name = Name, attrs = Attrs}) ->
      ["<", Name, attrs_to_iolist(Attrs, []), ">"];
  to_iolist(#xmlstreamend{name = Name}) ->
      ["</", Name, ">"];
  to_iolist(#xmlcdata{content = Content}) ->
      %% it's caller's responsibility to make sure that
      %% #xmlcdata's content is escaped properly!
      [Content]. %% ensure we return io*list*
  
  -spec to_pretty_iolist(#xmlstreamstart{} | #xmlstreamend{}
                         | xmlterm()) -> iolist().
  to_pretty_iolist(Term) ->
      to_pretty_iolist(Term, 0, "  ").
  
  %% `to_pretty_iolist/3' is generic enough to express `to_iolist/1'
  %% by passing an empty string as `Indent', but that would be less efficient,
  %% so let's leave the implementations separate.
  -spec to_pretty_iolist(#xmlstreamstart{} | #xmlstreamend{} | xmlterm(),
                         non_neg_integer(), string()) -> iolist().
  to_pretty_iolist(#xmlel{name = Name, attrs = Attrs, children = []},
                   Level, Indent) ->
      Shift = lists:duplicate(Level, Indent),
      [Shift, "<", Name, attrs_to_iolist(Attrs, []), "/>\n"];
  to_pretty_iolist(#xmlel{name = Name, attrs = Attrs,
                          children = [#xmlcdata{content = Content}]},
                   Level, Indent) ->
      Shift = lists:duplicate(Level, Indent),
      [Shift, "<", Name, attrs_to_iolist(Attrs, []), ">",
       Content, "</", Name, ">\n"];
  to_pretty_iolist(#xmlel{name = Name, attrs = Attrs, children = Children},
                   Level, Indent) ->
      Shift = lists:duplicate(Level, Indent),
      [Shift, "<", Name, attrs_to_iolist(Attrs, []), ">\n",
       [to_pretty_iolist(C, Level+1, Indent) || C <- Children],
       Shift, "</", Name, ">\n"];
  to_pretty_iolist(#xmlstreamstart{name = Name, attrs = Attrs}, Level, Indent) ->
      Shift = lists:duplicate(Level, Indent),
      [Shift, "<", Name, attrs_to_iolist(Attrs, []), ">\n"];
  to_pretty_iolist(#xmlstreamend{name = Name}, Level, Indent) ->
      Shift = lists:duplicate(Level, Indent),
      [Shift, "</", Name, ">\n"];
  to_pretty_iolist(#xmlcdata{content = Content}, Level, Indent) ->
      Shift = lists:duplicate(Level, Indent),
      [Shift, Content, "\n"].
  
  
negative.code: -spec unescape_attr_nif(binary()) -> binary().
  unescape_attr_nif(_Data) ->
      erlang:nif_error({?MODULE, nif_not_loaded}).
  