123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207(* This file is part of Markup.ml, released under the MIT license. See
LICENSE.md for details, or visit https://github.com/aantron/markup.ml. *)openCommonletlist_map_cps:('a->'bcps)->'alist->'blistcps=funflthrowk->letrecloopaccumulator=function|[]->k(List.revaccumulator)|x::l->fxthrow(funx'->loop(x'::accumulator)l)inloop[]lmoduleParsing=structtypecontext_entry={f:string->stringoption;previous:context_entry}typecontext=context_entryrefletparsequalified_name=tryletcolon_index=String.indexqualified_name':'inifcolon_index=0thenraiseNot_found;letprefix=String.subqualified_name0colon_indexinletsuffix=String.subqualified_name(colon_index+1)(String.lengthqualified_name-colon_index-1)inprefix,suffixwithNot_found->("",qualified_name)letinittop_level=letf=function|"xml"->Somexml_ns|"xmlns"->Somexmlns_ns|s->top_levelsinletrecentry={f;previous=entry}inrefentryletexpand_elementreportcontextraw_element_namethrowk=letns,name=parseraw_element_nameinmatch!context.fnswith|Someuri->k(uri,name)|None->matchnswith|""->k("",name)|prefix->report()(`Bad_namespaceprefix)throw(fun()->k(prefix,name))letpushreportcontextraw_element_nameraw_attributesthrowk=letparsed_attributes=raw_attributes|>List.map(fun(name,value)->parsename,value)inletf=parsed_attributes|>List.fold_left(funf->function|("xmlns",prefix),uri->(funp->ifp=prefixthenSomeurielsefp)|("","xmlns"),uri->(funp->ifp=""thenSomeurielsefp)|_->f)!context.finletentry={f;previous=!context}incontext:=entry;expand_elementreportcontextraw_element_namethrow(funexpanded_element_name->list_map_cpsbeginfun(name,value)_k->matchnamewith|"","xmlns"->k((xmlns_ns,"xmlns"),value)|"",name->k(("",name),value)|ns,name->matchfnswith|Someuri->k((uri,name),value)|None->report()(`Bad_namespacens)throw(fun()->k((ns,name),value))endparsed_attributesthrow(funexpanded_attributes->k(expanded_element_name,expanded_attributes)))letpop({contents={previous}}ascontext)=context:=previousendmoduleStringMap=Map.Make(String)moduleWriting=structtypecontext_entry={namespace_to_prefix:stringlistStringMap.t;prefix_to_namespace:stringStringMap.t;previous:context_entry}typecontext=context_entryref*(string->stringoption)letinittop_level=letnamespace_to_prefix=StringMap.empty|>StringMap.add""[""]|>StringMap.addxml_ns["xml"]|>StringMap.addxmlns_ns["xmlns"]inletprefix_to_namespace=StringMap.empty|>StringMap.add""""|>StringMap.add"xml"xml_ns|>StringMap.add"xmlns"xmlns_nsinletrecentry={namespace_to_prefix;prefix_to_namespace;previous=entry}inrefentry,top_levelletlookupreportallow_defaultcontextnamespacethrowk=letcandidate_prefixes=tryStringMap.findnamespace!(fstcontext).namespace_to_prefixwithNot_found->[]inletprefix=trySome(candidate_prefixes|>List.find(funprefix->(allow_default||prefix<>"")&&begintryStringMap.findprefix!(fstcontext).prefix_to_namespace=namespacewithNot_found->falseend))withNot_found->Noneinletprefix=matchprefixwith|Some_->prefix|None->matchsndcontextnamespacewith|None->None|Someprefix->ifnotallow_default&&prefix=""||StringMap.memprefix!(fstcontext).prefix_to_namespacethenNoneelseSomeprefixinmatchprefixwith|None->report()(`Bad_namespacenamespace)throw(fun()->k"")|Someprefix->kprefixletformatprefixname=matchprefixwith|""->name|prefix->prefix^":"^nameletunexpand_elementreportcontext(namespace,name)throwk=lookupreporttruecontextnamespacethrow(funprefix->k(formatprefixname))letunexpand_attributereportcontext((namespace,name),value)throwk=matchnamespacewith|""->k(name,value)|uri->ifuri=xmlns_ns&&name="xmlns"thenk("xmlns",value)elselookupreportfalsecontextnamespacethrow(funprefix->k(formatprefixname,value))letextendkvmap=letvs=tryStringMap.findkmapwithNot_found->[]inStringMap.addk(v::vs)mapletpushreportcontextelement_nameattributesthrowk=letnamespace_to_prefix,prefix_to_namespace=attributes|>List.fold_left(fun(ns_to_prefix,prefix_to_ns)->function|(ns,"xmlns"),uriwhenns=xmlns_ns->extenduri""ns_to_prefix,StringMap.add""uriprefix_to_ns|(ns,prefix),uriwhenns=xmlns_ns->extenduriprefixns_to_prefix,StringMap.addprefixuriprefix_to_ns|_->ns_to_prefix,prefix_to_ns)(!(fstcontext).namespace_to_prefix,!(fstcontext).prefix_to_namespace)inletentry={namespace_to_prefix;prefix_to_namespace;previous=!(fstcontext)}in(fstcontext):=entry;unexpand_elementreportcontextelement_namethrow(funelement_name->list_map_cps(unexpand_attributereportcontext)attributesthrow(funattributes->k(element_name,attributes)))letpop({contents={previous}},_ascontext)=(fstcontext):=previousend