anchor.diff:       {end_tag,"tag"}]},
      {"<a href=/a/bc/d.e>x</a>",
       [{tag,"a",[{"href","/a/bc/d.e"}]},
  -     {text,"x"},
  +     {text,<<"x">>},
        {end_tag,"a"}]},
      {"<a>...<...</a>",
       [{tag,"a",[]},
  -     {text,"...&lt;..."},
  +     {text,<<"...&lt;...">>},
        {end_tag,"a"}]},
      {"<P a=b c=d>hej<!-- tobbe --><b>svejsan</b>foo</p>grump<x x=y />",
       [{tag,"p",[{"a","b"},{"c","d"}]},
  -     {text,"hej"},
  +     {text,<<"hej">>},
        {comment," tobbe "},
        {tag,"b",[]},
  -     {text,"svejsan"},
  +     {text,<<"svejsan">>},
        {end_tag,"b"},
  -     {text,"foo"},
  +     {text,<<"foo">>},
        {end_tag,"p"},
  -     {text,"grump"},
  +     {text,<<"grump">>},
        {tag,"x",[{"x","y"}]},
        {end_tag,"x"}]},
      {"<script>visual+basic = rules;</script>",
  
positive.code: 
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %% Parsing real pages
  file_parse(File) ->
    {ok,B} = file:read_file(File),
    lists:reverse(sax(B,fun(T,A)-> [T|A] end, [])).
  
  wget_parse(Url) ->
    sax(wget(Url),fun(T,A)-> A++[T] end, []).
  
  wget_print(Url) ->
    io:fwrite("~s~n",[wget(Url)]).
  
  wget(Url) ->
    inets:start(),
    {ok, {_Rc, _Hdrs, Body}} = http:request(get, {Url, []}, [], []),
    Body.
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %% ad-hoc unit test
  
negative.code: -define(ev(X), ?ws(X); X==$>; X==$=).
  
  tokenize(Str) when is_integer(hd(Str))-> tokenize(list_to_binary(Str));
  tokenize(Str) when is_binary(Str) -> tokenize(tz(nil,Str));
  
  tokenize({TZ,Str}) ->
    tokenize(tz(TZ,Str));
  tokenize({text,Str,Token}) ->
    case ff(text,Str) of
      {{tag,""},EStr,{text,Txt}} -> 
        try [Token,{text,Txt}]++tokenize({{tag,""},EStr})
        catch _:_ -> tokenize({text,<<Txt/binary,"&lt;",EStr/binary>>,Token})
        end;
      {{text,Str},"",eof} ->
        [Token,{eof,{text,Str}}]
    end;
  tokenize({TZ,Str,Token}) ->
    [{Token,{TZ,Str}}].
  
  tz(nil,?m("<",Str))                       -> {{tag,""},ws(Str)};
  tz(nil,?d(_,Str))                         -> {nil,Str};
  
  tz({tag,""},?m("!--",Str))                -> {{comm,""},Str};
  tz({tag,""},?m("!",Str))                  -> {{'!',""},ws(Str)};
  tz({tag,""},?m("?",Str))                  -> {{que,""},ws(Str)};
  tz({tag,""},?m("/",Str))                  -> {{end_tag,""},ws(Str)};
  tz({tag,Tag},?D(X,S))when ?ev(X)          -> {{attr,"",{Tag,[]}},ws(S)};
  tz({tag,Tag},?d(X,Str))when ?ok(X)        -> {{tag,Tag++[X]},Str};
  
  tz({'!',DT},?m(">",Str))                  -> {text,Str,{'!',dc(DT)}};
  tz({'!',DT},?d(X,Str))                    -> {{'!',DT++[X]},Str};
  
  tz({que,DT},?m("?>",Str))                 -> {text,Str,{'?',dc(DT)}};
  tz({que,DT},?d(X,Str))                    -> {{que,DT++[X]},Str};
  
  tz({comm,Comm},?m("-->",Str))             -> {text,Str,{comment,Comm}};
  tz({comm,Comm},?d(X,Str))                 -> {{comm,Comm++[X]},Str};
  
  tz({etag,Tag,Attrs},?m("/>",Str))         -> {text,Str,{sc,Tag,Attrs}};
  tz({etag,"script",Attrs},?m(">",Str))     -> {script,Str,{open,"script",Attrs}};
  tz({etag,"style",Attrs},?m(">",Str))      -> {style,Str,{open,"style",Attrs}};
  tz({etag,Tag,Attrs},?m(">",Str))          -> {text,Str,{open,Tag,Attrs}};
  
  tz({end_tag,Tag},?D(X,S))when ?ev(X)      -> {{end_tag,Tag,'>'},ws(S)};
  tz({end_tag,Tag,'>'},?m(">",Str))         -> {text,Str,{close,dc(Tag)}};
  tz({end_tag,Tag},?d(X,Str))               -> {{end_tag,Tag++[X]},Str};
  
  tz({attr,"",{Tag,As}},?D(X,S))when ?ev(X) -> {{etag,dc(Tag),As},S};
  tz({attr,"",{Tag,As}},?M("/>",S))         -> {{etag,dc(Tag),As},S};
  tz({attr,A,{T,As}},?D(X,S))when ?ev(X)    -> {{eatt,{dc(A),T,As}},ws(S)};
  tz({attr,A,{T,As}},?M("/>",S))            -> {{eatt,{dc(A),T,As}},ws(S)};
  tz({attr,A,TAs},?d(X,Str))when ?ok(X)     -> {{attr,A++[X],TAs},Str};
  
  tz({eatt,ATAs},?m("=",Str))               -> {{val,ATAs},ws(Str)};
  tz({eatt,{A,T,As}},S)                     -> {{attr,"",{T,As++[{A,""}]}},ws(S)};
  
  tz({val,ATAs},?m("'",Str))                -> {{sqval,"",ATAs},Str};%singlequoted
  tz({val,ATAs},?m("\"",Str))               -> {{dqval,"",ATAs},Str};%doublequoted
  tz({val,ATAs},Str)                        -> {{uqval,"",ATAs},Str};%unquoted
  
  tz({sqval,V,{A,T,As}},?m("'",S))          -> {{attr,"",{T,As++[{A,V}]}},ws(S)};
  tz({sqval,V,ATAs},?d(X,Str))              -> {{sqval,V++[X],ATAs},Str};
  
  tz({dqval,V,{A,T,As}},?m("\"",S))         -> {{attr,"",{T,As++[{A,V}]}},ws(S)};
  tz({dqval,V,ATAs},?d(X,Str))              -> {{dqval,V++[X],ATAs},Str};
  
  tz({uqval,V,{A,T,As}},?D(X,S))when ?ev(X) -> {{attr,"",{T,As++[{A,V}]}},ws(S)};
  tz({uqval,V,{A,T,As}},?M("/>",S))         -> {{attr,"",{T,As++[{A,V}]}},ws(S)};
  tz({uqval,V,ATAs},?d(X,Str))              -> {{uqval,V++[X],ATAs},Str};
  
  tz(script,Str)                            -> ff(script,Str);
  tz(style,Str)                             -> ff(style,Str);
  tz(text,Str)                              -> ff(text,Str);
  
  tz(X,"")                                  -> {X,"",eof}.
  
  ff(What,Str) -> ff(What,Str,0,Str).
  
  ff(script,<<"</script>",Str/binary>>,N,Bin) -> 
    {Scr,_} = split_binary(Bin,N),
    {{tag,""},<<"/script>",Str/binary>>,{text,Scr}};
  ff(style,<<"</style>",Str/binary>>,N,Bin) -> 
    {Scr,_} = split_binary(Bin,N),
    {{tag,""},<<"/style>",Str/binary>>,{text,Scr}};
  ff(text,<<"<",Str/binary>>,N,Bin) -> 
    {Scr,_} = split_binary(Bin,N),
    {{tag,""},ws(Str),{text,Scr}};
  ff(_,<<>>,_,Str) -> 
    {{text,Str},"",eof};
  ff(What,<<_,Str/binary>>,N,Bin) -> 
    ff(What,Str,N+1,Bin).
  
  ws(?d(X,Str)) when ?ws(X) -> ws(Str);
  ws(Str) -> Str.
  