123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191(*
* oBus_xml_parser.ml
* ------------------
* Copyright : (c) 2009, Jeremie Dimino <jeremie@dimino.org>
* Licence : BSD3
*
* This file is a part of obus, an ocaml implementation of D-Bus.
*)openPrintfexceptionParse_failureofXmlm.pos*stringtypexml=|ElementofXmlm.pos*string*(string*string)list*xmllist|PCDataofXmlm.pos*stringtypenode_type=|NT_elementofstring|NT_pcdata|NT_any|NT_unionofnode_typelisttype'anode=node_type*(xml->'aoption)typexml_parser={position:Xmlm.pos;attributes:(string*string)list;mutablechildren:xmllist;}letfailwithpmsg=raise(Parse_failure(p.position,msg))letaopname=OBus_util.assocnamep.attributesletarpname=matchaopnamewith|Somev->v|None->ksprintf(failwithp)"attribute '%s' missing"nameletadpnamedefault=matchaopnamewith|Somev->v|None->defaultletafopnamefield=matchOBus_util.assocnamep.attributeswith|None->None|Somev->matchOBus_util.assocvfieldwith|Somev->Somev|None->ksprintf(failwithp)"unexpected value for '%s' (%s), must be one of %s"namev(String.concat", "(List.map(fun(name,v)->"'"^name^"'")field))letafrpnamefield=matchafopnamefieldwith|Somev->v|None->ksprintf(failwithp)"attribute '%s' missing"nameletafdpnamedefaultfield=matchafopnamefieldwith|Somev->v|None->defaultletexecutexml_parserp=tryletresult=xml_parserpinmatchp.childrenwith|[]->result|Element(pos,name,_,_)::_->ksprintf(failwithp)"unknown element '%s'"name|PCData(pos,_)::_->failwithp"trailing pc-data"with|Parse_failure_asexn->raiseexn|exn->failwithp(Printexc.to_stringexn)leteltnameelt_parser=(NT_elementname,function|Element(pos,name',attrs,children)whenname=name'->Some(executeelt_parser{position=pos;children=children;attributes=attrs})|_->None)letpcdata=(NT_pcdata,function|Element_->None|PCData(_,x)->Somex)letunionnodes=lettypes,fl=List.splitnodesin(NT_uniontypes,funnode->OBus_util.find_map(funf->fnode)fl)letmap(typ,f)g=(typ,funnode->OBus_util.map_option(fnode)g)letstring_of_typetyp=letrecflatacc=function|NT_unionl->List.fold_leftflataccl|NT_pcdata->"<pcdata>"::acc|NT_any->"<any>"::acc|NT_elementname->name::accinmatchflat[]typwith|[]->"<nothing>"|[x]->x|l->String.concat" or "lletoptp(typ,f)=matchOBus_util.part_mapfp.childrenwith|[],rest->None|[x],rest->p.children<-rest;Somex|_,rest->ksprintf(failwithp)"too many nodes of type %S"(string_of_typetyp)letonep(typ,f)=matchoptp(typ,f)with|Somex->x|None->ksprintf(failwithp)"element missing: %S"(string_of_typetyp)letanyp(typ,f)=letsuccess,rest=OBus_util.part_mapfp.childreninp.children<-rest;successletpos_of_xml=function|Element(pos,_,_,_)->pos|PCData(pos,_)->posletparsenodexml=execute(funp->onepnode){position=pos_of_xmlxml;attributes=[];children=[xml]}letinputinputnode=letrecmake()=letpos=Xmlm.posinputinmatchXmlm.inputinputwith|`El_start(("",name),attrs)->Element(pos,name,List.map(fun((uri,name),value)->(name,value))attrs,make_list())|`El_start((_,name),attrs)->(* Drops elements that are not part of the specification *)drop0;make()|`El_end->raise(Parse_failure(pos,"unexpected end of element"))|`Datastr->PCData(pos,str)|`Dtd_->make()andmake_list()=letpos=Xmlm.posinputinmatchXmlm.inputinputwith|`El_start(("",name),attrs)->letxml=Element(pos,name,List.map(fun((uri,name),value)->(name,value))attrs,make_list())inxml::make_list()|`El_start((_,name),attrs)->drop0;make_list()|`El_end->[]|`Datastr->letxml=PCData(pos,str)inxml::make_list()|`Dtd_->make_list()anddropdeep=matchXmlm.inputinputwith|`El_start_->drop(deep+1)|`El_end->ifdeep<>0thendrop(deep-1)|`Datastr->dropdeep|`Dtd_->dropdeepintryparsenode(make())withXmlm.Error(pos,error)->raise(Parse_failure(pos,Xmlm.error_messageerror))