123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423 |
- /*
- * transform.c: Implementation of the XSL Transformation 1.0 engine
- * transform part, i.e. applying a Stylesheet to a document
- *
- * References:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * Michael Kay "XSLT Programmer's Reference" pp 637-643
- * Writing Multiple Output Files
- *
- * XSLT-1.1 Working Draft
- * http://www.w3.org/TR/xslt11#multiple-output
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
- #define IN_LIBXSLT
- #include "libxslt.h"
- #include <limits.h>
- #include <string.h>
- #include <stdio.h>
- #include <stddef.h>
- #include <libxml/xmlmemory.h>
- #include <libxml/parser.h>
- #include <libxml/tree.h>
- #include <libxml/valid.h>
- #include <libxml/hash.h>
- #include <libxml/encoding.h>
- #include <libxml/xmlerror.h>
- #include <libxml/xpath.h>
- #include <libxml/parserInternals.h>
- #include <libxml/xpathInternals.h>
- #include <libxml/HTMLtree.h>
- #include <libxml/debugXML.h>
- #include <libxml/uri.h>
- #include "xslt.h"
- #include "xsltInternals.h"
- #include "xsltutils.h"
- #include "pattern.h"
- #include "transform.h"
- #include "variables.h"
- #include "numbersInternals.h"
- #include "namespaces.h"
- #include "attributes.h"
- #include "templates.h"
- #include "imports.h"
- #include "keys.h"
- #include "documents.h"
- #include "extensions.h"
- #include "extra.h"
- #include "preproc.h"
- #include "security.h"
- #ifdef WITH_XSLT_DEBUG
- #define WITH_XSLT_DEBUG_EXTRA
- #define WITH_XSLT_DEBUG_PROCESS
- #define WITH_XSLT_DEBUG_VARIABLE
- #endif
- #define XSLT_GENERATE_HTML_DOCTYPE
- #ifdef XSLT_GENERATE_HTML_DOCTYPE
- static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
- const xmlChar **systemID);
- #endif
- int xsltMaxDepth = 3000;
- int xsltMaxVars = 15000;
- /*
- * Useful macros
- */
- #ifndef FALSE
- # define FALSE (0 == 1)
- # define TRUE (!FALSE)
- #endif
- #define IS_BLANK_NODE(n) \
- (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
- /*
- * Forward declarations
- */
- static xmlNsPtr
- xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
- static xmlNodePtr
- xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
- xmlNodePtr node, xmlNodePtr insert, int isLRE,
- int topElemVisited);
- static void
- xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
- xmlNodePtr contextNode, xmlNodePtr list,
- xsltTemplatePtr templ);
- static void
- xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
- xmlNodePtr contextNode,
- xmlNodePtr list,
- xsltTemplatePtr templ,
- xsltStackElemPtr withParams);
- /**
- * templPush:
- * @ctxt: the transformation context
- * @value: the template to push on the stack
- *
- * Push a template on the stack
- *
- * Returns the new index in the stack or 0 in case of error
- */
- static int
- templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
- {
- if (ctxt->templMax == 0) {
- ctxt->templMax = 4;
- ctxt->templTab =
- (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
- sizeof(ctxt->templTab[0]));
- if (ctxt->templTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (0);
- }
- }
- else if (ctxt->templNr >= ctxt->templMax) {
- ctxt->templMax *= 2;
- ctxt->templTab =
- (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
- ctxt->templMax *
- sizeof(ctxt->templTab[0]));
- if (ctxt->templTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return (0);
- }
- }
- ctxt->templTab[ctxt->templNr] = value;
- ctxt->templ = value;
- return (ctxt->templNr++);
- }
- /**
- * templPop:
- * @ctxt: the transformation context
- *
- * Pop a template value from the stack
- *
- * Returns the stored template value
- */
- static xsltTemplatePtr
- templPop(xsltTransformContextPtr ctxt)
- {
- xsltTemplatePtr ret;
- if (ctxt->templNr <= 0)
- return (0);
- ctxt->templNr--;
- if (ctxt->templNr > 0)
- ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
- else
- ctxt->templ = (xsltTemplatePtr) 0;
- ret = ctxt->templTab[ctxt->templNr];
- ctxt->templTab[ctxt->templNr] = 0;
- return (ret);
- }
- /**
- * xsltLocalVariablePop:
- * @ctxt: the transformation context
- * @limitNr: number of variables which should remain
- * @level: the depth in the xsl:template's tree
- *
- * Pops all variable values at the given @depth from the stack.
- *
- * Returns the stored variable value
- * **NOTE:**
- * This is an internal routine and should not be called by users!
- */
- void
- xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
- {
- xsltStackElemPtr variable;
- if (ctxt->varsNr <= 0)
- return;
- do {
- if (ctxt->varsNr <= limitNr)
- break;
- variable = ctxt->varsTab[ctxt->varsNr - 1];
- if (variable->level <= level)
- break;
- if (variable->level >= 0)
- xsltFreeStackElemList(variable);
- ctxt->varsNr--;
- } while (ctxt->varsNr != 0);
- if (ctxt->varsNr > 0)
- ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
- else
- ctxt->vars = NULL;
- }
- /**
- * xsltTemplateParamsCleanup:
- *
- * Removes xsl:param and xsl:with-param items from the
- * variable-stack. Only xsl:with-param items are not freed.
- */
- static void
- xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
- {
- xsltStackElemPtr param;
- for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
- param = ctxt->varsTab[ctxt->varsNr -1];
- /*
- * Free xsl:param items.
- * xsl:with-param items will have a level of -1 or -2.
- */
- if (param->level >= 0) {
- xsltFreeStackElemList(param);
- }
- }
- if (ctxt->varsNr > 0)
- ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
- else
- ctxt->vars = NULL;
- }
- #ifdef WITH_PROFILER
- /**
- * profPush:
- * @ctxt: the transformation context
- * @value: the profiling value to push on the stack
- *
- * Push a profiling value on the stack
- *
- * Returns the new index in the stack or 0 in case of error
- */
- static int
- profPush(xsltTransformContextPtr ctxt, long value)
- {
- if (ctxt->profMax == 0) {
- ctxt->profMax = 4;
- ctxt->profTab =
- (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
- if (ctxt->profTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (0);
- }
- }
- else if (ctxt->profNr >= ctxt->profMax) {
- ctxt->profMax *= 2;
- ctxt->profTab =
- (long *) xmlRealloc(ctxt->profTab,
- ctxt->profMax * sizeof(ctxt->profTab[0]));
- if (ctxt->profTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return (0);
- }
- }
- ctxt->profTab[ctxt->profNr] = value;
- ctxt->prof = value;
- return (ctxt->profNr++);
- }
- /**
- * profPop:
- * @ctxt: the transformation context
- *
- * Pop a profiling value from the stack
- *
- * Returns the stored profiling value
- */
- static long
- profPop(xsltTransformContextPtr ctxt)
- {
- long ret;
- if (ctxt->profNr <= 0)
- return (0);
- ctxt->profNr--;
- if (ctxt->profNr > 0)
- ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
- else
- ctxt->prof = (long) 0;
- ret = ctxt->profTab[ctxt->profNr];
- ctxt->profTab[ctxt->profNr] = 0;
- return (ret);
- }
- static void
- profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
- {
- int i;
- if (templ->templMax == 0) {
- templ->templMax = 4;
- templ->templCalledTab =
- (xsltTemplatePtr *) xmlMalloc(templ->templMax *
- sizeof(templ->templCalledTab[0]));
- templ->templCountTab =
- (int *) xmlMalloc(templ->templMax *
- sizeof(templ->templCountTab[0]));
- if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return;
- }
- }
- else if (templ->templNr >= templ->templMax) {
- templ->templMax *= 2;
- templ->templCalledTab =
- (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab,
- templ->templMax *
- sizeof(templ->templCalledTab[0]));
- templ->templCountTab =
- (int *) xmlRealloc(templ->templCountTab,
- templ->templMax *
- sizeof(templ->templCountTab[0]));
- if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return;
- }
- }
- for (i = 0; i < templ->templNr; i++) {
- if (templ->templCalledTab[i] == parent) {
- templ->templCountTab[i]++;
- break;
- }
- }
- if (i == templ->templNr) {
- /* not found, add new one */
- templ->templCalledTab[templ->templNr] = parent;
- templ->templCountTab[templ->templNr] = 1;
- templ->templNr++;
- }
- }
- #endif /* WITH_PROFILER */
- /**
- * xsltPreCompEval:
- * @ctxt: transform context
- * @node: context node
- * @comp: precompiled expression
- *
- * Evaluate a precompiled XPath expression.
- */
- static xmlXPathObjectPtr
- xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltStylePreCompPtr comp) {
- xmlXPathObjectPtr res;
- xmlXPathContextPtr xpctxt;
- xmlNodePtr oldXPContextNode;
- xmlNsPtr *oldXPNamespaces;
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
- xpctxt = ctxt->xpathCtxt;
- oldXPContextNode = xpctxt->node;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPContextSize = xpctxt->contextSize;
- oldXPNsNr = xpctxt->nsNr;
- oldXPNamespaces = xpctxt->namespaces;
- xpctxt->node = node;
- #ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- xpctxt->namespaces = comp->inScopeNs->list;
- xpctxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- #else
- xpctxt->namespaces = comp->nsList;
- xpctxt->nsNr = comp->nsNr;
- #endif
- res = xmlXPathCompiledEval(comp->comp, xpctxt);
- xpctxt->node = oldXPContextNode;
- xpctxt->proximityPosition = oldXPProximityPosition;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->nsNr = oldXPNsNr;
- xpctxt->namespaces = oldXPNamespaces;
- return(res);
- }
- /**
- * xsltPreCompEvalToBoolean:
- * @ctxt: transform context
- * @node: context node
- * @comp: precompiled expression
- *
- * Evaluate a precompiled XPath expression as boolean.
- */
- static int
- xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltStylePreCompPtr comp) {
- int res;
- xmlXPathContextPtr xpctxt;
- xmlNodePtr oldXPContextNode;
- xmlNsPtr *oldXPNamespaces;
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
- xpctxt = ctxt->xpathCtxt;
- oldXPContextNode = xpctxt->node;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPContextSize = xpctxt->contextSize;
- oldXPNsNr = xpctxt->nsNr;
- oldXPNamespaces = xpctxt->namespaces;
- xpctxt->node = node;
- #ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- xpctxt->namespaces = comp->inScopeNs->list;
- xpctxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- #else
- xpctxt->namespaces = comp->nsList;
- xpctxt->nsNr = comp->nsNr;
- #endif
- res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
- xpctxt->node = oldXPContextNode;
- xpctxt->proximityPosition = oldXPProximityPosition;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->nsNr = oldXPNsNr;
- xpctxt->namespaces = oldXPNamespaces;
- return(res);
- }
- /************************************************************************
- * *
- * XInclude default settings *
- * *
- ************************************************************************/
- static int xsltDoXIncludeDefault = 0;
- /**
- * xsltSetXIncludeDefault:
- * @xinclude: whether to do XInclude processing
- *
- * Set whether XInclude should be processed on document being loaded by default
- */
- void
- xsltSetXIncludeDefault(int xinclude) {
- xsltDoXIncludeDefault = (xinclude != 0);
- }
- /**
- * xsltGetXIncludeDefault:
- *
- * Provides the default state for XInclude processing
- *
- * Returns 0 if there is no processing 1 otherwise
- */
- int
- xsltGetXIncludeDefault(void) {
- return(xsltDoXIncludeDefault);
- }
- static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
- /**
- * xsltDebugSetDefaultTrace:
- * @val: tracing level mask
- *
- * Set the default debug tracing level mask
- */
- void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
- xsltDefaultTrace = val;
- }
- /**
- * xsltDebugGetDefaultTrace:
- *
- * Get the current default debug tracing level mask
- *
- * Returns the current default debug tracing level mask
- */
- xsltDebugTraceCodes xsltDebugGetDefaultTrace() {
- return xsltDefaultTrace;
- }
- /************************************************************************
- * *
- * Handling of Transformation Contexts *
- * *
- ************************************************************************/
- static xsltTransformCachePtr
- xsltTransformCacheCreate(void)
- {
- xsltTransformCachePtr ret;
- ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
- if (ret == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltTransformCacheCreate : malloc failed\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltTransformCache));
- return(ret);
- }
- static void
- xsltTransformCacheFree(xsltTransformCachePtr cache)
- {
- if (cache == NULL)
- return;
- /*
- * Free tree fragments.
- */
- if (cache->RVT) {
- xmlDocPtr tmp, cur = cache->RVT;
- while (cur) {
- tmp = cur;
- cur = (xmlDocPtr) cur->next;
- if (tmp->_private != NULL) {
- /*
- * Tree the document info.
- */
- xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
- xmlFree(tmp->_private);
- }
- xmlFreeDoc(tmp);
- }
- }
- /*
- * Free vars/params.
- */
- if (cache->stackItems) {
- xsltStackElemPtr tmp, cur = cache->stackItems;
- while (cur) {
- tmp = cur;
- cur = cur->next;
- /*
- * REVISIT TODO: Should be call a destruction-function
- * instead?
- */
- xmlFree(tmp);
- }
- }
- xmlFree(cache);
- }
- /**
- * xsltNewTransformContext:
- * @style: a parsed XSLT stylesheet
- * @doc: the input document
- *
- * Create a new XSLT TransformContext
- *
- * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
- */
- xsltTransformContextPtr
- xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
- xsltTransformContextPtr cur;
- xsltDocumentPtr docu;
- int i;
- xsltInitGlobals();
- cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
- "xsltNewTransformContext : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltTransformContext));
- cur->cache = xsltTransformCacheCreate();
- if (cur->cache == NULL)
- goto internal_err;
- /*
- * setup of the dictionary must be done early as some of the
- * processing later like key handling may need it.
- */
- cur->dict = xmlDictCreateSub(style->dict);
- cur->internalized = ((style->internalized) && (cur->dict != NULL));
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "Creating sub-dictionary from stylesheet for transformation\n");
- #endif
- /*
- * initialize the template stack
- */
- cur->templTab = (xsltTemplatePtr *)
- xmlMalloc(10 * sizeof(xsltTemplatePtr));
- if (cur->templTab == NULL) {
- xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
- "xsltNewTransformContext: out of memory\n");
- goto internal_err;
- }
- cur->templNr = 0;
- cur->templMax = 5;
- cur->templ = NULL;
- cur->maxTemplateDepth = xsltMaxDepth;
- /*
- * initialize the variables stack
- */
- cur->varsTab = (xsltStackElemPtr *)
- xmlMalloc(10 * sizeof(xsltStackElemPtr));
- if (cur->varsTab == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltNewTransformContext: out of memory\n");
- goto internal_err;
- }
- cur->varsNr = 0;
- cur->varsMax = 10;
- cur->vars = NULL;
- cur->varsBase = 0;
- cur->maxTemplateVars = xsltMaxVars;
- /*
- * the profiling stack is not initialized by default
- */
- cur->profTab = NULL;
- cur->profNr = 0;
- cur->profMax = 0;
- cur->prof = 0;
- cur->style = style;
- xmlXPathInit();
- cur->xpathCtxt = xmlXPathNewContext(doc);
- if (cur->xpathCtxt == NULL) {
- xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
- "xsltNewTransformContext : xmlXPathNewContext failed\n");
- goto internal_err;
- }
- /*
- * Create an XPath cache.
- */
- if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
- goto internal_err;
- /*
- * Initialize the extras array
- */
- if (style->extrasNr != 0) {
- cur->extrasMax = style->extrasNr + 20;
- cur->extras = (xsltRuntimeExtraPtr)
- xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
- if (cur->extras == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltNewTransformContext: out of memory\n");
- goto internal_err;
- }
- cur->extrasNr = style->extrasNr;
- for (i = 0;i < cur->extrasMax;i++) {
- cur->extras[i].info = NULL;
- cur->extras[i].deallocate = NULL;
- cur->extras[i].val.ptr = NULL;
- }
- } else {
- cur->extras = NULL;
- cur->extrasNr = 0;
- cur->extrasMax = 0;
- }
- XSLT_REGISTER_VARIABLE_LOOKUP(cur);
- XSLT_REGISTER_FUNCTION_LOOKUP(cur);
- cur->xpathCtxt->nsHash = style->nsHash;
- /*
- * Initialize the registered external modules
- */
- xsltInitCtxtExts(cur);
- /*
- * Setup document element ordering for later efficiencies
- * (bug 133289)
- */
- if (xslDebugStatus == XSLT_DEBUG_NONE)
- xmlXPathOrderDocElems(doc);
- /*
- * Must set parserOptions before calling xsltNewDocument
- * (bug 164530)
- */
- cur->parserOptions = XSLT_PARSE_OPTIONS;
- docu = xsltNewDocument(cur, doc);
- if (docu == NULL) {
- xsltTransformError(cur, NULL, (xmlNodePtr)doc,
- "xsltNewTransformContext : xsltNewDocument failed\n");
- goto internal_err;
- }
- docu->main = 1;
- cur->document = docu;
- cur->inst = NULL;
- cur->outputFile = NULL;
- cur->sec = xsltGetDefaultSecurityPrefs();
- cur->debugStatus = xslDebugStatus;
- cur->traceCode = (unsigned long*) &xsltDefaultTrace;
- cur->xinclude = xsltGetXIncludeDefault();
- cur->keyInitLevel = 0;
- return(cur);
- internal_err:
- if (cur != NULL)
- xsltFreeTransformContext(cur);
- return(NULL);
- }
- /**
- * xsltFreeTransformContext:
- * @ctxt: an XSLT parser context
- *
- * Free up the memory allocated by @ctxt
- */
- void
- xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
- if (ctxt == NULL)
- return;
- /*
- * Shutdown the extension modules associated to the stylesheet
- * used if needed.
- */
- xsltShutdownCtxtExts(ctxt);
- if (ctxt->xpathCtxt != NULL) {
- ctxt->xpathCtxt->nsHash = NULL;
- xmlXPathFreeContext(ctxt->xpathCtxt);
- }
- if (ctxt->templTab != NULL)
- xmlFree(ctxt->templTab);
- if (ctxt->varsTab != NULL)
- xmlFree(ctxt->varsTab);
- if (ctxt->profTab != NULL)
- xmlFree(ctxt->profTab);
- if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
- int i;
- for (i = 0;i < ctxt->extrasNr;i++) {
- if ((ctxt->extras[i].deallocate != NULL) &&
- (ctxt->extras[i].info != NULL))
- ctxt->extras[i].deallocate(ctxt->extras[i].info);
- }
- xmlFree(ctxt->extras);
- }
- xsltFreeGlobalVariables(ctxt);
- xsltFreeDocuments(ctxt);
- xsltFreeCtxtExts(ctxt);
- xsltFreeRVTs(ctxt);
- xsltTransformCacheFree(ctxt->cache);
- xmlDictFree(ctxt->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "freeing transformation dictionary\n");
- #endif
- memset(ctxt, -1, sizeof(xsltTransformContext));
- xmlFree(ctxt);
- }
- /************************************************************************
- * *
- * Copy of Nodes in an XSLT fashion *
- * *
- ************************************************************************/
- /**
- * xsltAddChild:
- * @parent: the parent node
- * @cur: the child node
- *
- * Wrapper version of xmlAddChild with a more consistent behaviour on
- * error. One expect the use to be child = xsltAddChild(parent, child);
- * and the routine will take care of not leaking on errors or node merge
- *
- * Returns the child is successfully attached or NULL if merged or freed
- */
- static xmlNodePtr
- xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
- xmlNodePtr ret;
- if (cur == NULL)
- return(NULL);
- if (parent == NULL) {
- xmlFreeNode(cur);
- return(NULL);
- }
- ret = xmlAddChild(parent, cur);
- return(ret);
- }
- /**
- * xsltAddTextString:
- * @ctxt: a XSLT process context
- * @target: the text node where the text will be attached
- * @string: the text string
- * @len: the string length in byte
- *
- * Extend the current text node with the new string, it handles coalescing
- *
- * Returns: the text node
- */
- static xmlNodePtr
- xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
- const xmlChar *string, int len) {
- /*
- * optimization
- */
- if ((len <= 0) || (string == NULL) || (target == NULL))
- return(target);
- if (ctxt->lasttext == target->content) {
- int minSize;
- /* Check for integer overflow accounting for NUL terminator. */
- if (len >= INT_MAX - ctxt->lasttuse) {
- xsltTransformError(ctxt, NULL, target,
- "xsltCopyText: text allocation failed\n");
- return(NULL);
- }
- minSize = ctxt->lasttuse + len + 1;
- if (ctxt->lasttsize < minSize) {
- xmlChar *newbuf;
- int size;
- int extra;
- /* Double buffer size but increase by at least 100 bytes. */
- extra = minSize < 100 ? 100 : minSize;
- /* Check for integer overflow. */
- if (extra > INT_MAX - ctxt->lasttsize) {
- size = INT_MAX;
- }
- else {
- size = ctxt->lasttsize + extra;
- }
- newbuf = (xmlChar *) xmlRealloc(target->content,size);
- if (newbuf == NULL) {
- xsltTransformError(ctxt, NULL, target,
- "xsltCopyText: text allocation failed\n");
- return(NULL);
- }
- ctxt->lasttsize = size;
- ctxt->lasttext = newbuf;
- target->content = newbuf;
- }
- memcpy(&(target->content[ctxt->lasttuse]), string, len);
- ctxt->lasttuse += len;
- target->content[ctxt->lasttuse] = 0;
- } else {
- xmlNodeAddContent(target, string);
- ctxt->lasttext = target->content;
- len = xmlStrlen(target->content);
- ctxt->lasttsize = len;
- ctxt->lasttuse = len;
- }
- return(target);
- }
- /**
- * xsltCopyTextString:
- * @ctxt: a XSLT process context
- * @target: the element where the text will be attached
- * @string: the text string
- * @noescape: should disable-escaping be activated for this text node.
- *
- * Adds @string to a newly created or an existent text node child of
- * @target.
- *
- * Returns: the text node, where the text content of @cur is copied to.
- * NULL in case of API or internal errors.
- */
- xmlNodePtr
- xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
- const xmlChar *string, int noescape)
- {
- xmlNodePtr copy;
- int len;
- if (string == NULL)
- return(NULL);
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyTextString: copy text %s\n",
- string));
- #endif
- /*
- * Play safe and reset the merging mechanism for every new
- * target node.
- */
- if ((target == NULL) || (target->children == NULL)) {
- ctxt->lasttext = NULL;
- }
- /* handle coalescing of text nodes here */
- len = xmlStrlen(string);
- if ((ctxt->type == XSLT_OUTPUT_XML) &&
- (ctxt->style->cdataSection != NULL) &&
- (target != NULL) &&
- (target->type == XML_ELEMENT_NODE) &&
- (((target->ns == NULL) &&
- (xmlHashLookup2(ctxt->style->cdataSection,
- target->name, NULL) != NULL)) ||
- ((target->ns != NULL) &&
- (xmlHashLookup2(ctxt->style->cdataSection,
- target->name, target->ns->href) != NULL))))
- {
- /*
- * Process "cdata-section-elements".
- */
- if ((target->last != NULL) &&
- (target->last->type == XML_CDATA_SECTION_NODE))
- {
- return(xsltAddTextString(ctxt, target->last, string, len));
- }
- copy = xmlNewCDataBlock(ctxt->output, string, len);
- } else if (noescape) {
- /*
- * Process "disable-output-escaping".
- */
- if ((target != NULL) && (target->last != NULL) &&
- (target->last->type == XML_TEXT_NODE) &&
- (target->last->name == xmlStringTextNoenc))
- {
- return(xsltAddTextString(ctxt, target->last, string, len));
- }
- copy = xmlNewTextLen(string, len);
- if (copy != NULL)
- copy->name = xmlStringTextNoenc;
- } else {
- /*
- * Default processing.
- */
- if ((target != NULL) && (target->last != NULL) &&
- (target->last->type == XML_TEXT_NODE) &&
- (target->last->name == xmlStringText)) {
- return(xsltAddTextString(ctxt, target->last, string, len));
- }
- copy = xmlNewTextLen(string, len);
- }
- if (copy != NULL && target != NULL)
- copy = xsltAddChild(target, copy);
- if (copy != NULL) {
- ctxt->lasttext = copy->content;
- ctxt->lasttsize = len;
- ctxt->lasttuse = len;
- } else {
- xsltTransformError(ctxt, NULL, target,
- "xsltCopyTextString: text copy failed\n");
- ctxt->lasttext = NULL;
- }
- return(copy);
- }
- /**
- * xsltCopyText:
- * @ctxt: a XSLT process context
- * @target: the element where the text will be attached
- * @cur: the text or CDATA node
- * @interned: the string is in the target doc dictionary
- *
- * Copy the text content of @cur and append it to @target's children.
- *
- * Returns: the text node, where the text content of @cur is copied to.
- * NULL in case of API or internal errors.
- */
- static xmlNodePtr
- xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
- xmlNodePtr cur, int interned)
- {
- xmlNodePtr copy;
- if ((cur->type != XML_TEXT_NODE) &&
- (cur->type != XML_CDATA_SECTION_NODE))
- return(NULL);
- if (cur->content == NULL)
- return(NULL);
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (cur->type == XML_CDATA_SECTION_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyText: copy CDATA text %s\n",
- cur->content));
- } else if (cur->name == xmlStringTextNoenc) {
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyText: copy unescaped text %s\n",
- cur->content));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyText: copy text %s\n",
- cur->content));
- }
- #endif
- /*
- * Play save and reset the merging mechanism for every new
- * target node.
- */
- if ((target == NULL) || (target->children == NULL)) {
- ctxt->lasttext = NULL;
- }
- if ((ctxt->style->cdataSection != NULL) &&
- (ctxt->type == XSLT_OUTPUT_XML) &&
- (target != NULL) &&
- (target->type == XML_ELEMENT_NODE) &&
- (((target->ns == NULL) &&
- (xmlHashLookup2(ctxt->style->cdataSection,
- target->name, NULL) != NULL)) ||
- ((target->ns != NULL) &&
- (xmlHashLookup2(ctxt->style->cdataSection,
- target->name, target->ns->href) != NULL))))
- {
- /*
- * Process "cdata-section-elements".
- */
- /*
- * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
- */
- /*
- * TODO: Since this doesn't merge adjacent CDATA-section nodes,
- * we'll get: <![CDATA[x]]><!CDATA[y]]>.
- * TODO: Reported in #321505.
- */
- if ((target->last != NULL) &&
- (target->last->type == XML_CDATA_SECTION_NODE))
- {
- /*
- * Append to existing CDATA-section node.
- */
- copy = xsltAddTextString(ctxt, target->last, cur->content,
- xmlStrlen(cur->content));
- goto exit;
- } else {
- unsigned int len;
- len = xmlStrlen(cur->content);
- copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
- if (copy == NULL)
- goto exit;
- ctxt->lasttext = copy->content;
- ctxt->lasttsize = len;
- ctxt->lasttuse = len;
- }
- } else if ((target != NULL) &&
- (target->last != NULL) &&
- /* both escaped or both non-escaped text-nodes */
- (((target->last->type == XML_TEXT_NODE) &&
- (target->last->name == cur->name)) ||
- /* non-escaped text nodes and CDATA-section nodes */
- (((target->last->type == XML_CDATA_SECTION_NODE) &&
- (cur->name == xmlStringTextNoenc)))))
- {
- /*
- * we are appending to an existing text node
- */
- copy = xsltAddTextString(ctxt, target->last, cur->content,
- xmlStrlen(cur->content));
- goto exit;
- } else if ((interned) && (target != NULL) &&
- (target->doc != NULL) &&
- (target->doc->dict == ctxt->dict))
- {
- /*
- * TODO: DO we want to use this also for "text" output?
- */
- copy = xmlNewTextLen(NULL, 0);
- if (copy == NULL)
- goto exit;
- if (cur->name == xmlStringTextNoenc)
- copy->name = xmlStringTextNoenc;
- /*
- * Must confirm that content is in dict (bug 302821)
- * TODO: This check should be not needed for text coming
- * from the stylesheets
- */
- if (xmlDictOwns(ctxt->dict, cur->content))
- copy->content = cur->content;
- else {
- if ((copy->content = xmlStrdup(cur->content)) == NULL)
- return NULL;
- }
- ctxt->lasttext = NULL;
- } else {
- /*
- * normal processing. keep counters to extend the text node
- * in xsltAddTextString if needed.
- */
- unsigned int len;
- len = xmlStrlen(cur->content);
- copy = xmlNewTextLen(cur->content, len);
- if (copy == NULL)
- goto exit;
- if (cur->name == xmlStringTextNoenc)
- copy->name = xmlStringTextNoenc;
- ctxt->lasttext = copy->content;
- ctxt->lasttsize = len;
- ctxt->lasttuse = len;
- }
- if (copy != NULL) {
- if (target != NULL) {
- copy->doc = target->doc;
- /*
- * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
- * to ensure that the optimized text-merging mechanism
- * won't interfere with normal node-merging in any case.
- */
- copy = xsltAddChild(target, copy);
- }
- } else {
- xsltTransformError(ctxt, NULL, target,
- "xsltCopyText: text copy failed\n");
- }
- exit:
- if ((copy == NULL) || (copy->content == NULL)) {
- xsltTransformError(ctxt, NULL, target,
- "Internal error in xsltCopyText(): "
- "Failed to copy the string.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- }
- return(copy);
- }
- /**
- * xsltShallowCopyAttr:
- * @ctxt: a XSLT process context
- * @invocNode: responsible node in the stylesheet; used for error reports
- * @target: the element where the attribute will be grafted
- * @attr: the attribute to be copied
- *
- * Do a copy of an attribute.
- * Called by:
- * - xsltCopyTree()
- * - xsltCopyOf()
- * - xsltCopy()
- *
- * Returns: a new xmlAttrPtr, or NULL in case of error.
- */
- static xmlAttrPtr
- xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
- xmlNodePtr target, xmlAttrPtr attr)
- {
- xmlAttrPtr copy;
- xmlChar *value;
- if (attr == NULL)
- return(NULL);
- if (target->type != XML_ELEMENT_NODE) {
- xsltTransformError(ctxt, NULL, invocNode,
- "Cannot add an attribute node to a non-element node.\n");
- return(NULL);
- }
- if (target->children != NULL) {
- xsltTransformError(ctxt, NULL, invocNode,
- "Attribute nodes must be added before "
- "any child nodes to an element.\n");
- return(NULL);
- }
- value = xmlNodeListGetString(attr->doc, attr->children, 1);
- if (attr->ns != NULL) {
- xmlNsPtr ns;
- ns = xsltGetSpecialNamespace(ctxt, invocNode,
- attr->ns->href, attr->ns->prefix, target);
- if (ns == NULL) {
- xsltTransformError(ctxt, NULL, invocNode,
- "Namespace fixup error: Failed to acquire an in-scope "
- "namespace binding of the copied attribute '{%s}%s'.\n",
- attr->ns->href, attr->name);
- /*
- * TODO: Should we just stop here?
- */
- }
- /*
- * Note that xmlSetNsProp() will take care of duplicates
- * and assigns the new namespace even to a duplicate.
- */
- copy = xmlSetNsProp(target, ns, attr->name, value);
- } else {
- copy = xmlSetNsProp(target, NULL, attr->name, value);
- }
- if (value != NULL)
- xmlFree(value);
- if (copy == NULL)
- return(NULL);
- #if 0
- /*
- * NOTE: This was optimized according to bug #342695.
- * TODO: Can this further be optimized, if source and target
- * share the same dict and attr->children is just 1 text node
- * which is in the dict? How probable is such a case?
- */
- /*
- * TODO: Do we need to create an empty text node if the value
- * is the empty string?
- */
- value = xmlNodeListGetString(attr->doc, attr->children, 1);
- if (value != NULL) {
- txtNode = xmlNewDocText(target->doc, NULL);
- if (txtNode == NULL)
- return(NULL);
- if ((target->doc != NULL) &&
- (target->doc->dict != NULL))
- {
- txtNode->content =
- (xmlChar *) xmlDictLookup(target->doc->dict,
- BAD_CAST value, -1);
- xmlFree(value);
- } else
- txtNode->content = value;
- copy->children = txtNode;
- }
- #endif
- return(copy);
- }
- /**
- * xsltCopyAttrListNoOverwrite:
- * @ctxt: a XSLT process context
- * @invocNode: responsible node in the stylesheet; used for error reports
- * @target: the element where the new attributes will be grafted
- * @attr: the first attribute in the list to be copied
- *
- * Copies a list of attribute nodes, starting with @attr, over to the
- * @target element node.
- *
- * Called by:
- * - xsltCopyTree()
- *
- * Returns 0 on success and -1 on errors and internal errors.
- */
- static int
- xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
- xmlNodePtr invocNode,
- xmlNodePtr target, xmlAttrPtr attr)
- {
- xmlAttrPtr copy;
- xmlNsPtr origNs = NULL, copyNs = NULL;
- xmlChar *value;
- /*
- * Don't use xmlCopyProp() here, since it will try to
- * reconciliate namespaces.
- */
- while (attr != NULL) {
- /*
- * Find a namespace node in the tree of @target.
- * Avoid searching for the same ns.
- */
- if (attr->ns != origNs) {
- origNs = attr->ns;
- if (attr->ns != NULL) {
- copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
- attr->ns->href, attr->ns->prefix, target);
- if (copyNs == NULL)
- return(-1);
- } else
- copyNs = NULL;
- }
- /*
- * If attribute has a value, we need to copy it (watching out
- * for possible entities)
- */
- if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
- (attr->children->next == NULL)) {
- copy = xmlNewNsProp(target, copyNs, attr->name,
- attr->children->content);
- } else if (attr->children != NULL) {
- value = xmlNodeListGetString(attr->doc, attr->children, 1);
- copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
- xmlFree(value);
- } else {
- copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
- }
- if (copy == NULL)
- return(-1);
- attr = attr->next;
- }
- return(0);
- }
- /**
- * xsltShallowCopyElem:
- * @ctxt: the XSLT process context
- * @node: the element node in the source tree
- * or the Literal Result Element
- * @insert: the parent in the result tree
- * @isLRE: if @node is a Literal Result Element
- *
- * Make a copy of the element node @node
- * and insert it as last child of @insert.
- *
- * URGENT TODO: The problem with this one (for the non-refactored code)
- * is that it is used for both, Literal Result Elements *and*
- * copying input nodes.
- *
- * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
- *
- * Called from:
- * xsltApplySequenceConstructor()
- * (for Literal Result Elements - which is a problem)
- * xsltCopy() (for shallow-copying elements via xsl:copy)
- *
- * Returns a pointer to the new node, or NULL in case of error
- */
- static xmlNodePtr
- xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr insert, int isLRE)
- {
- xmlNodePtr copy;
- if ((node->type == XML_DTD_NODE) || (insert == NULL))
- return(NULL);
- if ((node->type == XML_TEXT_NODE) ||
- (node->type == XML_CDATA_SECTION_NODE))
- return(xsltCopyText(ctxt, insert, node, 0));
- copy = xmlDocCopyNode(node, insert->doc, 0);
- if (copy != NULL) {
- copy->doc = ctxt->output;
- copy = xsltAddChild(insert, copy);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, node,
- "xsltShallowCopyElem: copy failed\n");
- return (copy);
- }
- if (node->type == XML_ELEMENT_NODE) {
- /*
- * Add namespaces as they are needed
- */
- if (node->nsDef != NULL) {
- /*
- * TODO: Remove the LRE case in the refactored code
- * gets enabled.
- */
- if (isLRE)
- xsltCopyNamespaceList(ctxt, copy, node->nsDef);
- else
- xsltCopyNamespaceListInternal(copy, node->nsDef);
- }
- /*
- * URGENT TODO: The problem with this is that it does not
- * copy over all namespace nodes in scope.
- * The damn thing about this is, that we would need to
- * use the xmlGetNsList(), for every single node; this is
- * also done in xsltCopyTree(), but only for the top node.
- */
- if (node->ns != NULL) {
- if (isLRE) {
- /*
- * REVISIT TODO: Since the non-refactored code still does
- * ns-aliasing, we need to call xsltGetNamespace() here.
- * Remove this when ready.
- */
- copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
- } else {
- copy->ns = xsltGetSpecialNamespace(ctxt,
- node, node->ns->href, node->ns->prefix, copy);
- }
- } else if ((insert->type == XML_ELEMENT_NODE) &&
- (insert->ns != NULL))
- {
- /*
- * "Undeclare" the default namespace.
- */
- xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
- }
- }
- } else {
- xsltTransformError(ctxt, NULL, node,
- "xsltShallowCopyElem: copy %s failed\n", node->name);
- }
- return(copy);
- }
- /**
- * xsltCopyTreeList:
- * @ctxt: a XSLT process context
- * @invocNode: responsible node in the stylesheet; used for error reports
- * @list: the list of element nodes in the source tree.
- * @insert: the parent in the result tree.
- * @isLRE: is this a literal result element list
- * @topElemVisited: indicates if a top-most element was already processed
- *
- * Make a copy of the full list of tree @list
- * and insert it as last children of @insert
- *
- * NOTE: Not to be used for Literal Result Elements.
- *
- * Used by:
- * - xsltCopyOf()
- *
- * Returns a pointer to the new list, or NULL in case of error
- */
- static xmlNodePtr
- xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
- xmlNodePtr list,
- xmlNodePtr insert, int isLRE, int topElemVisited)
- {
- xmlNodePtr copy, ret = NULL;
- while (list != NULL) {
- copy = xsltCopyTree(ctxt, invocNode,
- list, insert, isLRE, topElemVisited);
- if (copy != NULL) {
- if (ret == NULL) {
- ret = copy;
- }
- }
- list = list->next;
- }
- return(ret);
- }
- /**
- * xsltCopyNamespaceListInternal:
- * @node: the target node
- * @cur: the first namespace
- *
- * Do a copy of a namespace list. If @node is non-NULL the
- * new namespaces are added automatically.
- * Called by:
- * xsltCopyTree()
- *
- * QUESTION: What is the exact difference between this function
- * and xsltCopyNamespaceList() in "namespaces.c"?
- * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
- *
- * Returns: a new xmlNsPtr, or NULL in case of error.
- */
- static xmlNsPtr
- xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
- xmlNsPtr ret = NULL;
- xmlNsPtr p = NULL, q, luNs;
- if (ns == NULL)
- return(NULL);
- /*
- * One can add namespaces only on element nodes
- */
- if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
- elem = NULL;
- do {
- if (ns->type != XML_NAMESPACE_DECL)
- break;
- /*
- * Avoid duplicating namespace declarations on the tree.
- */
- if (elem != NULL) {
- if ((elem->ns != NULL) &&
- xmlStrEqual(elem->ns->prefix, ns->prefix) &&
- xmlStrEqual(elem->ns->href, ns->href))
- {
- ns = ns->next;
- continue;
- }
- luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
- if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
- {
- ns = ns->next;
- continue;
- }
- }
- q = xmlNewNs(elem, ns->href, ns->prefix);
- if (p == NULL) {
- ret = p = q;
- } else if (q != NULL) {
- p->next = q;
- p = q;
- }
- ns = ns->next;
- } while (ns != NULL);
- return(ret);
- }
- /**
- * xsltShallowCopyNsNode:
- * @ctxt: the XSLT transformation context
- * @invocNode: responsible node in the stylesheet; used for error reports
- * @insert: the target element node in the result tree
- * @ns: the namespace node
- *
- * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
- *
- * Returns a new/existing ns-node, or NULL.
- */
- static xmlNsPtr
- xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
- xmlNodePtr invocNode,
- xmlNodePtr insert,
- xmlNsPtr ns)
- {
- /*
- * TODO: Contrary to header comments, this is declared as int.
- * be modified to return a node pointer, or NULL if any error
- */
- xmlNsPtr tmpns;
- if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
- return(NULL);
- if (insert->children != NULL) {
- xsltTransformError(ctxt, NULL, invocNode,
- "Namespace nodes must be added before "
- "any child nodes are added to an element.\n");
- return(NULL);
- }
- /*
- * BIG NOTE: Xalan-J simply overwrites any ns-decls with
- * an equal prefix. We definitively won't do that.
- *
- * MSXML 4.0 and the .NET ignores ns-decls for which an
- * equal prefix is already in use.
- *
- * Saxon raises an error like:
- * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
- * nodes with the same name".
- *
- * NOTE: We'll currently follow MSXML here.
- * REVISIT TODO: Check if it's better to follow Saxon here.
- */
- if (ns->prefix == NULL) {
- /*
- * If we are adding ns-nodes to an element using e.g.
- * <xsl:copy-of select="/foo/namespace::*">, then we need
- * to ensure that we don't incorrectly declare a default
- * namespace on an element in no namespace, which otherwise
- * would move the element incorrectly into a namespace, if
- * the node tree is serialized.
- */
- if (insert->ns == NULL)
- goto occupied;
- } else if ((ns->prefix[0] == 'x') &&
- xmlStrEqual(ns->prefix, BAD_CAST "xml"))
- {
- /*
- * The XML namespace is built in.
- */
- return(NULL);
- }
- if (insert->nsDef != NULL) {
- tmpns = insert->nsDef;
- do {
- if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
- if ((tmpns->prefix == ns->prefix) ||
- xmlStrEqual(tmpns->prefix, ns->prefix))
- {
- /*
- * Same prefix.
- */
- if (xmlStrEqual(tmpns->href, ns->href))
- return(NULL);
- goto occupied;
- }
- }
- tmpns = tmpns->next;
- } while (tmpns != NULL);
- }
- tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
- if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
- return(NULL);
- /*
- * Declare a new namespace.
- * TODO: The problem (wrt efficiency) with this xmlNewNs() is
- * that it will again search the already declared namespaces
- * for a duplicate :-/
- */
- return(xmlNewNs(insert, ns->href, ns->prefix));
- occupied:
- /*
- * TODO: We could as well raise an error here (like Saxon does),
- * or at least generate a warning.
- */
- return(NULL);
- }
- /**
- * xsltCopyTree:
- * @ctxt: the XSLT transformation context
- * @invocNode: responsible node in the stylesheet; used for error reports
- * @node: the element node in the source tree
- * @insert: the parent in the result tree
- * @isLRE: indicates if @node is a Literal Result Element
- * @topElemVisited: indicates if a top-most element was already processed
- *
- * Make a copy of the full tree under the element node @node
- * and insert it as last child of @insert
- *
- * NOTE: Not to be used for Literal Result Elements.
- *
- * Used by:
- * - xsltCopyOf()
- *
- * Returns a pointer to the new tree, or NULL in case of error
- */
- static xmlNodePtr
- xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
- xmlNodePtr node, xmlNodePtr insert, int isLRE,
- int topElemVisited)
- {
- xmlNodePtr copy;
- if (node == NULL)
- return(NULL);
- switch (node->type) {
- case XML_ELEMENT_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_NODE:
- case XML_PI_NODE:
- case XML_COMMENT_NODE:
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- #ifdef LIBXML_DOCB_ENABLED
- case XML_DOCB_DOCUMENT_NODE:
- #endif
- break;
- case XML_TEXT_NODE: {
- int noenc = (node->name == xmlStringTextNoenc);
- return(xsltCopyTextString(ctxt, insert, node->content, noenc));
- }
- case XML_CDATA_SECTION_NODE:
- return(xsltCopyTextString(ctxt, insert, node->content, 0));
- case XML_ATTRIBUTE_NODE:
- return((xmlNodePtr)
- xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
- case XML_NAMESPACE_DECL:
- return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
- insert, (xmlNsPtr) node));
- case XML_DOCUMENT_TYPE_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- case XML_NOTATION_NODE:
- case XML_DTD_NODE:
- case XML_ELEMENT_DECL:
- case XML_ATTRIBUTE_DECL:
- case XML_ENTITY_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- return(NULL);
- }
- if (XSLT_IS_RES_TREE_FRAG(node)) {
- if (node->children != NULL)
- copy = xsltCopyTreeList(ctxt, invocNode,
- node->children, insert, 0, 0);
- else
- copy = NULL;
- return(copy);
- }
- copy = xmlDocCopyNode(node, insert->doc, 0);
- if (copy != NULL) {
- copy->doc = ctxt->output;
- copy = xsltAddChild(insert, copy);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, invocNode,
- "xsltCopyTree: Copying of '%s' failed.\n", node->name);
- return (copy);
- }
- /*
- * The node may have been coalesced into another text node.
- */
- if (insert->last != copy)
- return(insert->last);
- copy->next = NULL;
- if (node->type == XML_ELEMENT_NODE) {
- /*
- * Copy in-scope namespace nodes.
- *
- * REVISIT: Since we try to reuse existing in-scope ns-decls by
- * using xmlSearchNsByHref(), this will eventually change
- * the prefix of an original ns-binding; thus it might
- * break QNames in element/attribute content.
- * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
- * context, plus a ns-lookup function, which writes directly
- * to a given list, then we wouldn't need to create/free the
- * nsList every time.
- */
- if ((topElemVisited == 0) &&
- (node->parent != NULL) &&
- (node->parent->type != XML_DOCUMENT_NODE) &&
- (node->parent->type != XML_HTML_DOCUMENT_NODE))
- {
- xmlNsPtr *nsList, *curns, ns;
- /*
- * If this is a top-most element in a tree to be
- * copied, then we need to ensure that all in-scope
- * namespaces are copied over. For nodes deeper in the
- * tree, it is sufficient to reconcile only the ns-decls
- * (node->nsDef entries).
- */
- nsList = xmlGetNsList(node->doc, node);
- if (nsList != NULL) {
- curns = nsList;
- do {
- /*
- * Search by prefix first in order to break as less
- * QNames in element/attribute content as possible.
- */
- ns = xmlSearchNs(insert->doc, insert,
- (*curns)->prefix);
- if ((ns == NULL) ||
- (! xmlStrEqual(ns->href, (*curns)->href)))
- {
- ns = NULL;
- /*
- * Search by namespace name.
- * REVISIT TODO: Currently disabled.
- */
- #if 0
- ns = xmlSearchNsByHref(insert->doc,
- insert, (*curns)->href);
- #endif
- }
- if (ns == NULL) {
- /*
- * Declare a new namespace on the copied element.
- */
- ns = xmlNewNs(copy, (*curns)->href,
- (*curns)->prefix);
- /* TODO: Handle errors */
- }
- if (node->ns == *curns) {
- /*
- * If this was the original's namespace then set
- * the generated counterpart on the copy.
- */
- copy->ns = ns;
- }
- curns++;
- } while (*curns != NULL);
- xmlFree(nsList);
- }
- } else if (node->nsDef != NULL) {
- /*
- * Copy over all namespace declaration attributes.
- */
- if (node->nsDef != NULL) {
- if (isLRE)
- xsltCopyNamespaceList(ctxt, copy, node->nsDef);
- else
- xsltCopyNamespaceListInternal(copy, node->nsDef);
- }
- }
- /*
- * Set the namespace.
- */
- if (node->ns != NULL) {
- if (copy->ns == NULL) {
- /*
- * This will map copy->ns to one of the newly created
- * in-scope ns-decls, OR create a new ns-decl on @copy.
- */
- copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
- node->ns->href, node->ns->prefix, copy);
- }
- } else if ((insert->type == XML_ELEMENT_NODE) &&
- (insert->ns != NULL))
- {
- /*
- * "Undeclare" the default namespace on @copy with xmlns="".
- */
- xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
- }
- /*
- * Copy attribute nodes.
- */
- if (node->properties != NULL) {
- xsltCopyAttrListNoOverwrite(ctxt, invocNode,
- copy, node->properties);
- }
- if (topElemVisited == 0)
- topElemVisited = 1;
- }
- /*
- * Copy the subtree.
- */
- if (node->children != NULL) {
- xsltCopyTreeList(ctxt, invocNode,
- node->children, copy, isLRE, topElemVisited);
- }
- } else {
- xsltTransformError(ctxt, NULL, invocNode,
- "xsltCopyTree: Copying of '%s' failed.\n", node->name);
- }
- return(copy);
- }
- /************************************************************************
- * *
- * Error/fallback processing *
- * *
- ************************************************************************/
- /**
- * xsltApplyFallbacks:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the node generating the error
- *
- * Process possible xsl:fallback nodes present under @inst
- *
- * Returns the number of xsl:fallback element found and processed
- */
- static int
- xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst) {
- xmlNodePtr child;
- int ret = 0;
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
- (inst->children == NULL))
- return(0);
- child = inst->children;
- while (child != NULL) {
- if ((IS_XSLT_ELEM(child)) &&
- (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "applying xsl:fallback\n");
- #endif
- ret++;
- xsltApplySequenceConstructor(ctxt, node, child->children,
- NULL);
- }
- child = child->next;
- }
- return(ret);
- }
- /************************************************************************
- * *
- * Default processing *
- * *
- ************************************************************************/
- /**
- * xsltDefaultProcessOneNode:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @params: extra parameters passed to the template if any
- *
- * Process the source node with the default built-in template rule:
- * <xsl:template match="*|/">
- * <xsl:apply-templates/>
- * </xsl:template>
- *
- * and
- *
- * <xsl:template match="text()|@*">
- * <xsl:value-of select="."/>
- * </xsl:template>
- *
- * Note also that namespace declarations are copied directly:
- *
- * the built-in template rule is the only template rule that is applied
- * for namespace nodes.
- */
- static void
- xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltStackElemPtr params) {
- xmlNodePtr copy;
- xmlNodePtr cur;
- int nbchild = 0, oldSize;
- int childno = 0, oldPos;
- xsltTemplatePtr template;
- CHECK_STOPPED;
- /*
- * Handling of leaves
- */
- switch (node->type) {
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_ELEMENT_NODE:
- break;
- case XML_CDATA_SECTION_NODE:
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy CDATA %s\n",
- node->content));
- #endif
- copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, node,
- "xsltDefaultProcessOneNode: cdata copy failed\n");
- }
- return;
- case XML_TEXT_NODE:
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (node->content == NULL) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy empty text\n"));
- return;
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy text %s\n",
- node->content));
- }
- #endif
- copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, node,
- "xsltDefaultProcessOneNode: text copy failed\n");
- }
- return;
- case XML_ATTRIBUTE_NODE:
- cur = node->children;
- while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
- cur = cur->next;
- if (cur == NULL) {
- xsltTransformError(ctxt, NULL, node,
- "xsltDefaultProcessOneNode: no text for attribute\n");
- } else {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (cur->content == NULL) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy empty text\n"));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy text %s\n",
- cur->content));
- }
- #endif
- copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, node,
- "xsltDefaultProcessOneNode: text copy failed\n");
- }
- }
- return;
- default:
- return;
- }
- /*
- * Handling of Elements: first pass, counting
- */
- cur = node->children;
- while (cur != NULL) {
- if (IS_XSLT_REAL_NODE(cur))
- nbchild++;
- cur = cur->next;
- }
- /*
- * Handling of Elements: second pass, actual processing
- *
- * Note that params are passed to the next template. This matches
- * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
- */
- oldSize = ctxt->xpathCtxt->contextSize;
- oldPos = ctxt->xpathCtxt->proximityPosition;
- cur = node->children;
- while (cur != NULL) {
- childno++;
- switch (cur->type) {
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_ELEMENT_NODE:
- ctxt->xpathCtxt->contextSize = nbchild;
- ctxt->xpathCtxt->proximityPosition = childno;
- xsltProcessOneNode(ctxt, cur, params);
- break;
- case XML_CDATA_SECTION_NODE:
- template = xsltGetTemplate(ctxt, cur, NULL);
- if (template) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
- cur->content));
- #endif
- /*
- * Instantiate the xsl:template.
- */
- xsltApplyXSLTTemplate(ctxt, cur, template->content,
- template, params);
- } else /* if (ctxt->mode == NULL) */ {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy CDATA %s\n",
- cur->content));
- #endif
- copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsltDefaultProcessOneNode: cdata copy failed\n");
- }
- }
- break;
- case XML_TEXT_NODE:
- template = xsltGetTemplate(ctxt, cur, NULL);
- if (template) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: applying template for text %s\n",
- cur->content));
- #endif
- ctxt->xpathCtxt->contextSize = nbchild;
- ctxt->xpathCtxt->proximityPosition = childno;
- /*
- * Instantiate the xsl:template.
- */
- xsltApplyXSLTTemplate(ctxt, cur, template->content,
- template, params);
- } else /* if (ctxt->mode == NULL) */ {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (cur->content == NULL) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy empty text\n"));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: copy text %s\n",
- cur->content));
- }
- #endif
- copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsltDefaultProcessOneNode: text copy failed\n");
- }
- }
- break;
- case XML_PI_NODE:
- case XML_COMMENT_NODE:
- template = xsltGetTemplate(ctxt, cur, NULL);
- if (template) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (cur->type == XML_PI_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: template found for PI %s\n",
- cur->name));
- } else if (cur->type == XML_COMMENT_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltDefaultProcessOneNode: template found for comment\n"));
- }
- #endif
- ctxt->xpathCtxt->contextSize = nbchild;
- ctxt->xpathCtxt->proximityPosition = childno;
- /*
- * Instantiate the xsl:template.
- */
- xsltApplyXSLTTemplate(ctxt, cur, template->content,
- template, params);
- }
- break;
- default:
- break;
- }
- cur = cur->next;
- }
- ctxt->xpathCtxt->contextSize = oldSize;
- ctxt->xpathCtxt->proximityPosition = oldPos;
- }
- /**
- * xsltProcessOneNode:
- * @ctxt: a XSLT process context
- * @contextNode: the "current node" in the source tree
- * @withParams: extra parameters (e.g. xsl:with-param) passed to the
- * template if any
- *
- * Process the source node.
- */
- void
- xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
- xsltStackElemPtr withParams)
- {
- xsltTemplatePtr templ;
- xmlNodePtr oldNode;
- templ = xsltGetTemplate(ctxt, contextNode, NULL);
- /*
- * If no template is found, apply the default rule.
- */
- if (templ == NULL) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (contextNode->type == XML_DOCUMENT_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for /\n"));
- } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for CDATA\n"));
- } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for attribute %s\n",
- ((xmlAttrPtr) contextNode)->name));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for %s\n", contextNode->name));
- }
- #endif
- oldNode = ctxt->node;
- ctxt->node = contextNode;
- xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
- ctxt->node = oldNode;
- return;
- }
- if (contextNode->type == XML_ATTRIBUTE_NODE) {
- xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
- /*
- * Set the "current template rule".
- */
- ctxt->currentTemplateRule = templ;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: applying template '%s' for attribute %s\n",
- templ->match, contextNode->name));
- #endif
- xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
- ctxt->currentTemplateRule = oldCurTempRule;
- } else {
- xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
- /*
- * Set the "current template rule".
- */
- ctxt->currentTemplateRule = templ;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (contextNode->type == XML_DOCUMENT_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: applying template '%s' for /\n",
- templ->match));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: applying template '%s' for %s\n",
- templ->match, contextNode->name));
- }
- #endif
- xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
- ctxt->currentTemplateRule = oldCurTempRule;
- }
- }
- #ifdef WITH_DEBUGGER
- static xmlNodePtr
- xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
- xmlNodePtr contextNode,
- xmlNodePtr list,
- xsltTemplatePtr templ,
- int *addCallResult)
- {
- xmlNodePtr debugedNode = NULL;
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
- if (templ) {
- *addCallResult = xslAddCall(templ, templ->elem);
- } else {
- *addCallResult = xslAddCall(NULL, list);
- }
- switch (ctxt->debugStatus) {
- case XSLT_DEBUG_RUN_RESTART:
- case XSLT_DEBUG_QUIT:
- if (*addCallResult)
- xslDropCall();
- return(NULL);
- }
- if (templ) {
- xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
- debugedNode = templ->elem;
- } else if (list) {
- xslHandleDebugger(list, contextNode, templ, ctxt);
- debugedNode = list;
- } else if (ctxt->inst) {
- xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
- debugedNode = ctxt->inst;
- }
- }
- return(debugedNode);
- }
- #endif /* WITH_DEBUGGER */
- /**
- * xsltLocalVariablePush:
- * @ctxt: the transformation context
- * @variable: variable to be pushed to the variable stack
- * @level: new value for variable's level
- *
- * Places the variable onto the local variable stack
- *
- * Returns: 0 for success, -1 for any error
- * **NOTE:**
- * This is an internal routine and should not be called by users!
- */
- int
- xsltLocalVariablePush(xsltTransformContextPtr ctxt,
- xsltStackElemPtr variable,
- int level)
- {
- if (ctxt->varsMax == 0) {
- ctxt->varsMax = 10;
- ctxt->varsTab =
- (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
- sizeof(ctxt->varsTab[0]));
- if (ctxt->varsTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (-1);
- }
- }
- if (ctxt->varsNr >= ctxt->varsMax) {
- ctxt->varsMax *= 2;
- ctxt->varsTab =
- (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
- ctxt->varsMax *
- sizeof(ctxt->varsTab[0]));
- if (ctxt->varsTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return (-1);
- }
- }
- ctxt->varsTab[ctxt->varsNr++] = variable;
- ctxt->vars = variable;
- variable->level = level;
- return(0);
- }
- /**
- * xsltReleaseLocalRVTs:
- *
- * Fragments which are results of extension instructions
- * are preserved; all other fragments are freed/cached.
- */
- static void
- xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
- {
- xmlDocPtr cur = ctxt->localRVT, tmp;
- if (cur == base)
- return;
- if (cur->prev != NULL)
- xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
- /* Reset localRVT early because some RVTs might be registered again. */
- ctxt->localRVT = base;
- if (base != NULL)
- base->prev = NULL;
- do {
- tmp = cur;
- cur = (xmlDocPtr) cur->next;
- if (tmp->psvi == XSLT_RVT_LOCAL) {
- xsltReleaseRVT(ctxt, tmp);
- } else if (tmp->psvi == XSLT_RVT_GLOBAL) {
- xsltRegisterPersistRVT(ctxt, tmp);
- } else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) {
- /*
- * This will either register the RVT again or move it to the
- * context variable.
- */
- xsltRegisterLocalRVT(ctxt, tmp);
- tmp->psvi = XSLT_RVT_FUNC_RESULT;
- } else {
- xmlGenericError(xmlGenericErrorContext,
- "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
- tmp->psvi);
- }
- } while (cur != base);
- }
- /**
- * xsltApplySequenceConstructor:
- * @ctxt: a XSLT process context
- * @contextNode: the "current node" in the source tree
- * @list: the nodes of a sequence constructor;
- * (plus leading xsl:param elements)
- * @templ: the compiled xsl:template (optional)
- *
- * Processes a sequence constructor.
- *
- * NOTE: ctxt->currentTemplateRule was introduced to reflect the
- * semantics of "current template rule". I.e. the field ctxt->templ
- * is not intended to reflect this, thus always pushed onto the
- * template stack.
- */
- static void
- xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
- xmlNodePtr contextNode, xmlNodePtr list,
- xsltTemplatePtr templ)
- {
- xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
- xmlNodePtr cur, insert, copy = NULL;
- int level = 0, oldVarsNr;
- xmlDocPtr oldLocalFragmentTop;
- #ifdef XSLT_REFACTORED
- xsltStylePreCompPtr info;
- #endif
- #ifdef WITH_DEBUGGER
- int addCallResult = 0;
- xmlNodePtr debuggedNode = NULL;
- #endif
- if (ctxt == NULL)
- return;
- #ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
- debuggedNode =
- xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
- list, templ, &addCallResult);
- if (debuggedNode == NULL)
- return;
- }
- #endif
- if (list == NULL)
- return;
- CHECK_STOPPED;
- /*
- * Check for infinite recursion: stop if the maximum of nested templates
- * is excceeded. Adjust xsltMaxDepth if you need more.
- */
- if (ctxt->depth >= ctxt->maxTemplateDepth) {
- xsltTransformError(ctxt, NULL, list,
- "xsltApplySequenceConstructor: A potential infinite template "
- "recursion was detected.\n"
- "You can adjust xsltMaxDepth (--maxdepth) in order to "
- "raise the maximum number of nested template calls and "
- "variables/params (currently set to %d).\n",
- ctxt->maxTemplateDepth);
- xsltDebug(ctxt, contextNode, list, NULL);
- ctxt->state = XSLT_STATE_STOPPED;
- return;
- }
- ctxt->depth++;
- oldLocalFragmentTop = ctxt->localRVT;
- oldInsert = insert = ctxt->insert;
- oldInst = oldCurInst = ctxt->inst;
- oldContextNode = ctxt->node;
- /*
- * Save current number of variables on the stack; new vars are popped when
- * exiting.
- */
- oldVarsNr = ctxt->varsNr;
- /*
- * Process the sequence constructor.
- */
- cur = list;
- while (cur != NULL) {
- if (ctxt->opLimit != 0) {
- if (ctxt->opCount >= ctxt->opLimit) {
- xsltTransformError(ctxt, NULL, cur,
- "xsltApplySequenceConstructor: "
- "Operation limit exceeded\n");
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- ctxt->opCount += 1;
- }
- ctxt->inst = cur;
- #ifdef WITH_DEBUGGER
- switch (ctxt->debugStatus) {
- case XSLT_DEBUG_RUN_RESTART:
- case XSLT_DEBUG_QUIT:
- break;
- }
- #endif
- /*
- * Test; we must have a valid insertion point.
- */
- if (insert == NULL) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: insert == NULL !\n"));
- #endif
- goto error;
- }
- #ifdef WITH_DEBUGGER
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
- xslHandleDebugger(cur, contextNode, templ, ctxt);
- #endif
- #ifdef XSLT_REFACTORED
- if (cur->type == XML_ELEMENT_NODE) {
- info = (xsltStylePreCompPtr) cur->psvi;
- /*
- * We expect a compiled representation on:
- * 1) XSLT instructions of this XSLT version (1.0)
- * (with a few exceptions)
- * 2) Literal result elements
- * 3) Extension instructions
- * 4) XSLT instructions of future XSLT versions
- * (forwards-compatible mode).
- */
- if (info == NULL) {
- /*
- * Handle the rare cases where we don't expect a compiled
- * representation on an XSLT element.
- */
- if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
- xsltMessage(ctxt, contextNode, cur);
- goto skip_children;
- }
- /*
- * Something really went wrong:
- */
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in xsltApplySequenceConstructor(): "
- "The element '%s' in the stylesheet has no compiled "
- "representation.\n",
- cur->name);
- goto skip_children;
- }
- if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
- xsltStyleItemLRElementInfoPtr lrInfo =
- (xsltStyleItemLRElementInfoPtr) info;
- /*
- * Literal result elements
- * --------------------------------------------------------
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy literal result "
- "element '%s'\n", cur->name));
- #endif
- /*
- * Copy the raw element-node.
- * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
- * == NULL)
- * goto error;
- */
- copy = xmlDocCopyNode(cur, insert->doc, 0);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in xsltApplySequenceConstructor(): "
- "Failed to copy literal result element '%s'.\n",
- cur->name);
- goto error;
- } else {
- /*
- * Add the element-node to the result tree.
- */
- copy->doc = ctxt->output;
- copy = xsltAddChild(insert, copy);
- /*
- * Create effective namespaces declarations.
- * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
- */
- if (lrInfo->effectiveNs != NULL) {
- xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
- xmlNsPtr ns, lastns = NULL;
- while (effNs != NULL) {
- /*
- * Avoid generating redundant namespace
- * declarations; thus lookup if there is already
- * such a ns-decl in the result.
- */
- ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
- if ((ns != NULL) &&
- (xmlStrEqual(ns->href, effNs->nsName)))
- {
- effNs = effNs->next;
- continue;
- }
- ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
- if (ns == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in "
- "xsltApplySequenceConstructor(): "
- "Failed to copy a namespace "
- "declaration.\n");
- goto error;
- }
- if (lastns == NULL)
- copy->nsDef = ns;
- else
- lastns->next =ns;
- lastns = ns;
- effNs = effNs->next;
- }
- }
- /*
- * NOTE that we don't need to apply ns-alising: this was
- * already done at compile-time.
- */
- if (cur->ns != NULL) {
- /*
- * If there's no such ns-decl in the result tree,
- * then xsltGetSpecialNamespace() will
- * create a ns-decl on the copied node.
- */
- copy->ns = xsltGetSpecialNamespace(ctxt, cur,
- cur->ns->href, cur->ns->prefix, copy);
- } else {
- /*
- * Undeclare the default namespace if needed.
- * This can be skipped, if the result element has
- * no ns-decls, in which case the result element
- * obviously does not declare a default namespace;
- * AND there's either no parent, or the parent
- * element is in no namespace; this means there's no
- * default namespace is scope to care about.
- *
- * REVISIT: This might result in massive
- * generation of ns-decls if nodes in a default
- * namespaces are mixed with nodes in no namespace.
- *
- */
- if (copy->nsDef ||
- ((insert != NULL) &&
- (insert->type == XML_ELEMENT_NODE) &&
- (insert->ns != NULL)))
- {
- xsltGetSpecialNamespace(ctxt, cur,
- NULL, NULL, copy);
- }
- }
- }
- /*
- * SPEC XSLT 2.0 "Each attribute of the literal result
- * element, other than an attribute in the XSLT namespace,
- * is processed to produce an attribute for the element in
- * the result tree."
- * NOTE: See bug #341325.
- */
- if (cur->properties != NULL) {
- xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
- }
- } else if (IS_XSLT_ELEM_FAST(cur)) {
- /*
- * XSLT instructions
- * --------------------------------------------------------
- */
- if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
- /*
- * We hit an unknown XSLT element.
- * Try to apply one of the fallback cases.
- */
- ctxt->insert = insert;
- if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
- xsltTransformError(ctxt, NULL, cur,
- "The is no fallback behaviour defined for "
- "the unknown XSLT element '%s'.\n",
- cur->name);
- }
- ctxt->insert = oldInsert;
- } else if (info->func != NULL) {
- /*
- * Execute the XSLT instruction.
- */
- ctxt->insert = insert;
- info->func(ctxt, contextNode, cur,
- (xsltElemPreCompPtr) info);
- /*
- * Cleanup temporary tree fragments.
- */
- if (oldLocalFragmentTop != ctxt->localRVT)
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
- ctxt->insert = oldInsert;
- } else if (info->type == XSLT_FUNC_VARIABLE) {
- xsltStackElemPtr tmpvar = ctxt->vars;
- xsltParseStylesheetVariable(ctxt, cur);
- if (tmpvar != ctxt->vars) {
- /*
- * TODO: Using a @tmpvar is an annoying workaround, but
- * the current mechanisms do not provide any other way
- * of knowing if the var was really pushed onto the
- * stack.
- */
- ctxt->vars->level = level;
- }
- } else if (info->type == XSLT_FUNC_MESSAGE) {
- /*
- * TODO: Won't be hit, since we don't compile xsl:message.
- */
- xsltMessage(ctxt, contextNode, cur);
- } else {
- xsltTransformError(ctxt, NULL, cur,
- "Unexpected XSLT element '%s'.\n", cur->name);
- }
- goto skip_children;
- } else {
- xsltTransformFunction func;
- /*
- * Extension intructions (elements)
- * --------------------------------------------------------
- */
- if (cur->psvi == xsltExtMarker) {
- /*
- * The xsltExtMarker was set during the compilation
- * of extension instructions if there was no registered
- * handler for this specific extension function at
- * compile-time.
- * Libxslt will now lookup if a handler is
- * registered in the context of this transformation.
- */
- func = xsltExtElementLookup(ctxt, cur->name,
- cur->ns->href);
- } else
- func = ((xsltElemPreCompPtr) cur->psvi)->func;
- if (func == NULL) {
- /*
- * No handler available.
- * Try to execute fallback behaviour via xsl:fallback.
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: unknown extension %s\n",
- cur->name));
- #endif
- ctxt->insert = insert;
- if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
- xsltTransformError(ctxt, NULL, cur,
- "Unknown extension instruction '{%s}%s'.\n",
- cur->ns->href, cur->name);
- }
- ctxt->insert = oldInsert;
- } else {
- /*
- * Execute the handler-callback.
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: extension construct %s\n",
- cur->name));
- #endif
- /*
- * Disable the xsltCopyTextString optimization for
- * extension elements. Extensions could append text using
- * xmlAddChild which will free the buffer pointed to by
- * 'lasttext'. This buffer could later be reallocated with
- * a different size than recorded in 'lasttsize'. See bug
- * #777432.
- */
- if (cur->psvi == xsltExtMarker) {
- ctxt->lasttext = NULL;
- }
- ctxt->insert = insert;
- func(ctxt, contextNode, cur, cur->psvi);
- /*
- * Cleanup temporary tree fragments.
- */
- if (oldLocalFragmentTop != ctxt->localRVT)
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
- ctxt->insert = oldInsert;
- }
- goto skip_children;
- }
- } else if (XSLT_IS_TEXT_NODE(cur)) {
- /*
- * Text
- * ------------------------------------------------------------
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (cur->name == xmlStringTextNoenc) {
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
- cur->content));
- } else {
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy text '%s'\n",
- cur->content));
- }
- #endif
- if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
- goto error;
- }
- #else /* XSLT_REFACTORED */
- if (IS_XSLT_ELEM(cur)) {
- /*
- * This is an XSLT node
- */
- xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
- if (info == NULL) {
- if (IS_XSLT_NAME(cur, "message")) {
- xsltMessage(ctxt, contextNode, cur);
- } else {
- /*
- * That's an error try to apply one of the fallback cases
- */
- ctxt->insert = insert;
- if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltApplySequenceConstructor: %s was not compiled\n",
- cur->name);
- }
- ctxt->insert = oldInsert;
- }
- goto skip_children;
- }
- if (info->func != NULL) {
- oldCurInst = ctxt->inst;
- ctxt->inst = cur;
- ctxt->insert = insert;
- info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
- /*
- * Cleanup temporary tree fragments.
- */
- if (oldLocalFragmentTop != ctxt->localRVT)
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
- ctxt->insert = oldInsert;
- ctxt->inst = oldCurInst;
- goto skip_children;
- }
- if (IS_XSLT_NAME(cur, "variable")) {
- xsltStackElemPtr tmpvar = ctxt->vars;
- oldCurInst = ctxt->inst;
- ctxt->inst = cur;
- xsltParseStylesheetVariable(ctxt, cur);
- ctxt->inst = oldCurInst;
- if (tmpvar != ctxt->vars) {
- /*
- * TODO: Using a @tmpvar is an annoying workaround, but
- * the current mechanisms do not provide any other way
- * of knowing if the var was really pushed onto the
- * stack.
- */
- ctxt->vars->level = level;
- }
- } else if (IS_XSLT_NAME(cur, "message")) {
- xsltMessage(ctxt, contextNode, cur);
- } else {
- xsltTransformError(ctxt, NULL, cur,
- "Unexpected XSLT element '%s'.\n", cur->name);
- }
- goto skip_children;
- } else if ((cur->type == XML_TEXT_NODE) ||
- (cur->type == XML_CDATA_SECTION_NODE)) {
- /*
- * This text comes from the stylesheet
- * For stylesheets, the set of whitespace-preserving
- * element names consists of just xsl:text.
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (cur->type == XML_CDATA_SECTION_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy CDATA text %s\n",
- cur->content));
- } else if (cur->name == xmlStringTextNoenc) {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy unescaped text %s\n",
- cur->content));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy text %s\n",
- cur->content));
- }
- #endif
- if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
- goto error;
- } else if ((cur->type == XML_ELEMENT_NODE) &&
- (cur->ns != NULL) && (cur->psvi != NULL)) {
- xsltTransformFunction function;
- oldCurInst = ctxt->inst;
- ctxt->inst = cur;
- /*
- * Flagged as an extension element
- */
- if (cur->psvi == xsltExtMarker)
- function = xsltExtElementLookup(ctxt, cur->name,
- cur->ns->href);
- else
- function = ((xsltElemPreCompPtr) cur->psvi)->func;
- if (function == NULL) {
- xmlNodePtr child;
- int found = 0;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: unknown extension %s\n",
- cur->name));
- #endif
- /*
- * Search if there are fallbacks
- */
- ctxt->insert = insert;
- child = cur->children;
- while (child != NULL) {
- if ((IS_XSLT_ELEM(child)) &&
- (IS_XSLT_NAME(child, "fallback")))
- {
- found = 1;
- xsltApplySequenceConstructor(ctxt, contextNode,
- child->children, NULL);
- }
- child = child->next;
- }
- ctxt->insert = oldInsert;
- if (!found) {
- xsltTransformError(ctxt, NULL, cur,
- "xsltApplySequenceConstructor: failed to find extension %s\n",
- cur->name);
- }
- } else {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: extension construct %s\n",
- cur->name));
- #endif
- /*
- * Disable the xsltCopyTextString optimization for
- * extension elements. Extensions could append text using
- * xmlAddChild which will free the buffer pointed to by
- * 'lasttext'. This buffer could later be reallocated with
- * a different size than recorded in 'lasttsize'. See bug
- * #777432.
- */
- if (cur->psvi == xsltExtMarker) {
- ctxt->lasttext = NULL;
- }
- ctxt->insert = insert;
- function(ctxt, contextNode, cur, cur->psvi);
- /*
- * Cleanup temporary tree fragments.
- */
- if (oldLocalFragmentTop != ctxt->localRVT)
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
- ctxt->insert = oldInsert;
- }
- ctxt->inst = oldCurInst;
- goto skip_children;
- } else if (cur->type == XML_ELEMENT_NODE) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplySequenceConstructor: copy node %s\n",
- cur->name));
- #endif
- oldCurInst = ctxt->inst;
- ctxt->inst = cur;
- if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
- goto error;
- /*
- * Add extra namespaces inherited from the current template
- * if we are in the first level children and this is a
- * "real" template.
- */
- if ((templ != NULL) && (oldInsert == insert) &&
- (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
- int i;
- xmlNsPtr ns, ret;
- for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
- const xmlChar *URI = NULL;
- xsltStylesheetPtr style;
- ns = ctxt->templ->inheritedNs[i];
- /* Note that the XSLT namespace was already excluded
- * in xsltGetInheritedNsList().
- */
- #if 0
- if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
- continue;
- #endif
- style = ctxt->style;
- while (style != NULL) {
- if (style->nsAliases != NULL)
- URI = (const xmlChar *)
- xmlHashLookup(style->nsAliases, ns->href);
- if (URI != NULL)
- break;
- style = xsltNextImport(style);
- }
- if (URI == UNDEFINED_DEFAULT_NS)
- continue;
- if (URI == NULL)
- URI = ns->href;
- /*
- * TODO: The following will still be buggy for the
- * non-refactored code.
- */
- ret = xmlSearchNs(copy->doc, copy, ns->prefix);
- if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
- {
- xmlNewNs(copy, URI, ns->prefix);
- }
- }
- if (copy->ns != NULL) {
- /*
- * Fix the node namespace if needed
- */
- copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
- }
- }
- /*
- * all the attributes are directly inherited
- */
- if (cur->properties != NULL) {
- xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
- }
- ctxt->inst = oldCurInst;
- }
- #endif /* else of XSLT_REFACTORED */
- /*
- * Descend into content in document order.
- */
- if (cur->children != NULL) {
- if (cur->children->type != XML_ENTITY_DECL) {
- cur = cur->children;
- level++;
- if (copy != NULL)
- insert = copy;
- continue;
- }
- }
- skip_children:
- /*
- * If xslt:message was just processed, we might have hit a
- * terminate='yes'; if so, then break the loop and clean up.
- * TODO: Do we need to check this also before trying to descend
- * into the content?
- */
- if (ctxt->state == XSLT_STATE_STOPPED)
- break;
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
- do {
- cur = cur->parent;
- level--;
- /*
- * Pop variables/params (xsl:variable and xsl:param).
- */
- if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
- xsltLocalVariablePop(ctxt, oldVarsNr, level);
- }
- insert = insert->parent;
- if (cur == NULL)
- break;
- if (cur == list->parent) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- error:
- /*
- * In case of errors: pop remaining variables.
- */
- if (ctxt->varsNr > oldVarsNr)
- xsltLocalVariablePop(ctxt, oldVarsNr, -1);
- ctxt->node = oldContextNode;
- ctxt->inst = oldInst;
- ctxt->insert = oldInsert;
- ctxt->depth--;
- #ifdef WITH_DEBUGGER
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
- xslDropCall();
- }
- #endif
- }
- /*
- * xsltApplyXSLTTemplate:
- * @ctxt: a XSLT transformation context
- * @contextNode: the node in the source tree.
- * @list: the nodes of a sequence constructor;
- * (plus leading xsl:param elements)
- * @templ: the compiled xsl:template declaration;
- * NULL if a sequence constructor
- * @withParams: a set of caller-parameters (xsl:with-param) or NULL
- *
- * Called by:
- * - xsltApplyImports()
- * - xsltCallTemplate()
- * - xsltDefaultProcessOneNode()
- * - xsltProcessOneNode()
- */
- static void
- xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
- xmlNodePtr contextNode,
- xmlNodePtr list,
- xsltTemplatePtr templ,
- xsltStackElemPtr withParams)
- {
- int oldVarsBase = 0;
- xmlNodePtr cur;
- xsltStackElemPtr tmpParam = NULL;
- xmlDocPtr oldUserFragmentTop;
- #ifdef WITH_PROFILER
- long start = 0;
- #endif
- #ifdef XSLT_REFACTORED
- xsltStyleItemParamPtr iparam;
- #else
- xsltStylePreCompPtr iparam;
- #endif
- #ifdef WITH_DEBUGGER
- int addCallResult = 0;
- #endif
- if (ctxt == NULL)
- return;
- if (templ == NULL) {
- xsltTransformError(ctxt, NULL, list,
- "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
- return;
- }
- #ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
- if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
- list, templ, &addCallResult) == NULL)
- return;
- }
- #endif
- if (list == NULL)
- return;
- CHECK_STOPPED;
- if (ctxt->varsNr >= ctxt->maxTemplateVars)
- {
- xsltTransformError(ctxt, NULL, list,
- "xsltApplyXSLTTemplate: A potential infinite template recursion "
- "was detected.\n"
- "You can adjust maxTemplateVars (--maxvars) in order to "
- "raise the maximum number of variables/params (currently set to %d).\n",
- ctxt->maxTemplateVars);
- xsltDebug(ctxt, contextNode, list, NULL);
- ctxt->state = XSLT_STATE_STOPPED;
- return;
- }
- oldUserFragmentTop = ctxt->tmpRVT;
- ctxt->tmpRVT = NULL;
- /*
- * Initiate a distinct scope of local params/variables.
- */
- oldVarsBase = ctxt->varsBase;
- ctxt->varsBase = ctxt->varsNr;
- ctxt->node = contextNode;
- #ifdef WITH_PROFILER
- if (ctxt->profile) {
- templ->nbCalls++;
- start = xsltTimestamp();
- profPush(ctxt, 0);
- profCallgraphAdd(templ, ctxt->templ);
- }
- #endif
- /*
- * Push the xsl:template declaration onto the stack.
- */
- templPush(ctxt, templ);
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (templ->name != NULL)
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "applying xsl:template '%s'\n", templ->name));
- #endif
- /*
- * Process xsl:param instructions and skip those elements for
- * further processing.
- */
- cur = list;
- do {
- if (cur->type == XML_TEXT_NODE) {
- cur = cur->next;
- continue;
- }
- if ((cur->type != XML_ELEMENT_NODE) ||
- (cur->name[0] != 'p') ||
- (cur->psvi == NULL) ||
- (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
- (! IS_XSLT_ELEM(cur)))
- {
- break;
- }
- list = cur->next;
- #ifdef XSLT_REFACTORED
- iparam = (xsltStyleItemParamPtr) cur->psvi;
- #else
- iparam = (xsltStylePreCompPtr) cur->psvi;
- #endif
- /*
- * Substitute xsl:param for a given xsl:with-param.
- * Since the XPath expression will reference the params/vars
- * by index, we need to slot the xsl:with-params in the
- * order of encountered xsl:params to keep the sequence of
- * params/variables in the stack exactly as it was at
- * compile time,
- */
- tmpParam = NULL;
- if (withParams) {
- tmpParam = withParams;
- do {
- if ((tmpParam->name == (iparam->name)) &&
- (tmpParam->nameURI == (iparam->ns)))
- {
- /*
- * Push the caller-parameter.
- */
- xsltLocalVariablePush(ctxt, tmpParam, -1);
- break;
- }
- tmpParam = tmpParam->next;
- } while (tmpParam != NULL);
- }
- /*
- * Push the xsl:param.
- */
- if (tmpParam == NULL) {
- /*
- * Note that we must assume that the added parameter
- * has a @depth of 0.
- */
- xsltParseStylesheetParam(ctxt, cur);
- }
- cur = cur->next;
- } while (cur != NULL);
- /*
- * Process the sequence constructor.
- */
- xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
- /*
- * Remove remaining xsl:param and xsl:with-param items from
- * the stack. Don't free xsl:with-param items.
- */
- if (ctxt->varsNr > ctxt->varsBase)
- xsltTemplateParamsCleanup(ctxt);
- ctxt->varsBase = oldVarsBase;
- /*
- * Release user-created fragments stored in the scope
- * of xsl:template. Note that this mechanism is deprecated:
- * user code should now use xsltRegisterLocalRVT() instead
- * of the obsolete xsltRegisterTmpRVT().
- */
- if (ctxt->tmpRVT) {
- xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
- while (curdoc != NULL) {
- tmp = curdoc;
- curdoc = (xmlDocPtr) curdoc->next;
- xsltReleaseRVT(ctxt, tmp);
- }
- }
- ctxt->tmpRVT = oldUserFragmentTop;
- /*
- * Pop the xsl:template declaration from the stack.
- */
- templPop(ctxt);
- #ifdef WITH_PROFILER
- if (ctxt->profile) {
- long spent, child, total, end;
- end = xsltTimestamp();
- child = profPop(ctxt);
- total = end - start;
- spent = total - child;
- if (spent <= 0) {
- /*
- * Not possible unless the original calibration failed
- * we can try to correct it on the fly.
- */
- xsltCalibrateAdjust(spent);
- spent = 0;
- }
- templ->time += spent;
- if (ctxt->profNr > 0)
- ctxt->profTab[ctxt->profNr - 1] += total;
- }
- #endif
- #ifdef WITH_DEBUGGER
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
- xslDropCall();
- }
- #endif
- }
- /**
- * xsltApplyOneTemplate:
- * @ctxt: a XSLT process context
- * @contextNode: the node in the source tree.
- * @list: the nodes of a sequence constructor
- * @templ: not used
- * @params: a set of parameters (xsl:param) or NULL
- *
- * Processes a sequence constructor on the current node in the source tree.
- *
- * @params are the already computed variable stack items; this function
- * pushes them on the variable stack, and pops them before exiting; it's
- * left to the caller to free or reuse @params afterwards. The initial
- * states of the variable stack will always be restored before this
- * function exits.
- * NOTE that this does *not* initiate a new distinct variable scope; i.e.
- * variables already on the stack are visible to the process. The caller's
- * side needs to start a new variable scope if needed (e.g. in exsl:function).
- *
- * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
- * provide a @templ); a non-NULL @templ might raise an error in the future.
- *
- * BIG NOTE: This function is not intended to process the content of an
- * xsl:template; it does not expect xsl:param instructions in @list and
- * will report errors if found.
- *
- * Called by:
- * - xsltEvalVariable() (variables.c)
- * - exsltFuncFunctionFunction() (libexsl/functions.c)
- */
- void
- xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
- xmlNodePtr contextNode,
- xmlNodePtr list,
- xsltTemplatePtr templ ATTRIBUTE_UNUSED,
- xsltStackElemPtr params)
- {
- if ((ctxt == NULL) || (list == NULL))
- return;
- CHECK_STOPPED;
- if (params) {
- /*
- * This code should be obsolete - was previously used
- * by libexslt/functions.c, but due to bug 381319 the
- * logic there was changed.
- */
- int oldVarsNr = ctxt->varsNr;
- /*
- * Push the given xsl:param(s) onto the variable stack.
- */
- while (params != NULL) {
- xsltLocalVariablePush(ctxt, params, -1);
- params = params->next;
- }
- xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
- /*
- * Pop the given xsl:param(s) from the stack but don't free them.
- */
- xsltLocalVariablePop(ctxt, oldVarsNr, -2);
- } else
- xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
- }
- /************************************************************************
- * *
- * XSLT-1.1 extensions *
- * *
- ************************************************************************/
- /**
- * xsltDocumentElem:
- * @ctxt: an XSLT processing context
- * @node: The current node
- * @inst: the instruction in the stylesheet
- * @castedComp: precomputed information
- *
- * Process an EXSLT/XSLT-1.1 document element
- */
- void
- xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xsltStylesheetPtr style = NULL;
- int ret;
- xmlChar *filename = NULL, *prop, *elements;
- xmlChar *element, *end;
- xmlDocPtr res = NULL;
- xmlDocPtr oldOutput;
- xmlNodePtr oldInsert, root;
- const char *oldOutputFile;
- xsltOutputType oldType;
- xmlChar *URL = NULL;
- const xmlChar *method;
- const xmlChar *doctypePublic;
- const xmlChar *doctypeSystem;
- const xmlChar *version;
- const xmlChar *encoding;
- int redirect_write_append = 0;
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
- return;
- if (comp->filename == NULL) {
- if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
- /*
- * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
- * (http://icl.com/saxon)
- * The @file is in no namespace.
- */
- #ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found saxon:output extension\n");
- #endif
- URL = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "file",
- XSLT_SAXON_NAMESPACE);
- if (URL == NULL)
- URL = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "href",
- XSLT_SAXON_NAMESPACE);
- } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
- #ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found xalan:write extension\n");
- #endif
- URL = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "select",
- XSLT_XALAN_NAMESPACE);
- if (URL != NULL) {
- xmlXPathCompExprPtr cmp;
- xmlChar *val;
- /*
- * Trying to handle bug #59212
- * The value of the "select" attribute is an
- * XPath expression.
- * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
- */
- cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL);
- val = xsltEvalXPathString(ctxt, cmp);
- xmlXPathFreeCompExpr(cmp);
- xmlFree(URL);
- URL = val;
- }
- if (URL == NULL)
- URL = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "file",
- XSLT_XALAN_NAMESPACE);
- if (URL == NULL)
- URL = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "href",
- XSLT_XALAN_NAMESPACE);
- } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
- URL = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "href",
- NULL);
- }
- } else {
- URL = xmlStrdup(comp->filename);
- }
- if (URL == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: href/URI-Reference not found\n");
- return;
- }
- /*
- * If the computation failed, it's likely that the URL wasn't escaped
- */
- filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
- if (filename == NULL) {
- xmlChar *escURL;
- escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
- if (escURL != NULL) {
- filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
- xmlFree(escURL);
- }
- }
- if (filename == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: URL computation failed for %s\n",
- URL);
- xmlFree(URL);
- return;
- }
- /*
- * Security checking: can we write to this resource
- */
- if (ctxt->sec != NULL) {
- ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
- if (ret <= 0) {
- if (ret == 0)
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: write rights for %s denied\n",
- filename);
- xmlFree(URL);
- xmlFree(filename);
- return;
- }
- }
- oldOutputFile = ctxt->outputFile;
- oldOutput = ctxt->output;
- oldInsert = ctxt->insert;
- oldType = ctxt->type;
- ctxt->outputFile = (const char *) filename;
- style = xsltNewStylesheet();
- if (style == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: out of memory\n");
- goto error;
- }
- /*
- * Version described in 1.1 draft allows full parameterization
- * of the output.
- */
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "version",
- NULL);
- if (prop != NULL) {
- if (style->version != NULL)
- xmlFree(style->version);
- style->version = prop;
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "encoding",
- NULL);
- if (prop != NULL) {
- if (style->encoding != NULL)
- xmlFree(style->encoding);
- style->encoding = prop;
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "method",
- NULL);
- if (prop != NULL) {
- const xmlChar *URI;
- if (style->method != NULL)
- xmlFree(style->method);
- style->method = NULL;
- if (style->methodURI != NULL)
- xmlFree(style->methodURI);
- style->methodURI = NULL;
- URI = xsltGetQNameURI(inst, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- } else if (URI == NULL) {
- if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
- (xmlStrEqual(prop, (const xmlChar *) "html")) ||
- (xmlStrEqual(prop, (const xmlChar *) "text"))) {
- style->method = prop;
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "invalid value for method: %s\n", prop);
- if (style != NULL) style->warnings++;
- }
- } else {
- style->method = prop;
- style->methodURI = xmlStrdup(URI);
- }
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "doctype-system", NULL);
- if (prop != NULL) {
- if (style->doctypeSystem != NULL)
- xmlFree(style->doctypeSystem);
- style->doctypeSystem = prop;
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "doctype-public", NULL);
- if (prop != NULL) {
- if (style->doctypePublic != NULL)
- xmlFree(style->doctypePublic);
- style->doctypePublic = prop;
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "standalone",
- NULL);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
- style->standalone = 1;
- } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
- style->standalone = 0;
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "invalid value for standalone: %s\n",
- prop);
- if (style != NULL) style->warnings++;
- }
- xmlFree(prop);
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "indent",
- NULL);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
- style->indent = 1;
- } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
- style->indent = 0;
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "invalid value for indent: %s\n", prop);
- if (style != NULL) style->warnings++;
- }
- xmlFree(prop);
- }
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "omit-xml-declaration",
- NULL);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
- style->omitXmlDeclaration = 1;
- } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
- style->omitXmlDeclaration = 0;
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "invalid value for omit-xml-declaration: %s\n",
- prop);
- if (style != NULL) style->warnings++;
- }
- xmlFree(prop);
- }
- elements = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)
- "cdata-section-elements",
- NULL);
- if (elements != NULL) {
- if (style->stripSpaces == NULL)
- style->stripSpaces = xmlHashCreate(10);
- if (style->stripSpaces == NULL) {
- xmlFree(elements);
- return;
- }
- element = elements;
- while (*element != 0) {
- while (IS_BLANK_CH(*element))
- element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK_CH(*end)))
- end++;
- element = xmlStrndup(element, end - element);
- if (element) {
- const xmlChar *URI;
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add cdata section output element %s\n",
- element);
- #endif
- URI = xsltGetQNameURI(inst, &element);
- xmlHashAddEntry2(style->stripSpaces, element, URI,
- (xmlChar *) "cdata");
- xmlFree(element);
- }
- element = end;
- }
- xmlFree(elements);
- }
- /*
- * Create a new document tree and process the element template
- */
- XSLT_GET_IMPORT_PTR(method, style, method)
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
- XSLT_GET_IMPORT_PTR(version, style, version)
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- if ((method != NULL) &&
- (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
- if (xmlStrEqual(method, (const xmlChar *) "html")) {
- ctxt->type = XSLT_OUTPUT_HTML;
- if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
- res = htmlNewDoc(doctypeSystem, doctypePublic);
- else {
- if (version != NULL) {
- #ifdef XSLT_GENERATE_HTML_DOCTYPE
- xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
- #endif
- }
- res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
- }
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: unsupported method xhtml\n");
- ctxt->type = XSLT_OUTPUT_HTML;
- res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
- ctxt->type = XSLT_OUTPUT_TEXT;
- res = xmlNewDoc(style->version);
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for output\n");
- #endif
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: unsupported method (%s)\n",
- method);
- goto error;
- }
- } else {
- ctxt->type = XSLT_OUTPUT_XML;
- res = xmlNewDoc(style->version);
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for output\n");
- #endif
- }
- res->charset = XML_CHAR_ENCODING_UTF8;
- if (encoding != NULL)
- res->encoding = xmlStrdup(encoding);
- ctxt->output = res;
- ctxt->insert = (xmlNodePtr) res;
- xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
- /*
- * Do some post processing work depending on the generated output
- */
- root = xmlDocGetRootElement(res);
- if (root != NULL) {
- const xmlChar *doctype = NULL;
- if ((root->ns != NULL) && (root->ns->prefix != NULL))
- doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
- if (doctype == NULL)
- doctype = root->name;
- /*
- * Apply the default selection of the method
- */
- if ((method == NULL) &&
- (root->ns == NULL) &&
- (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
- xmlNodePtr tmp;
- tmp = res->children;
- while ((tmp != NULL) && (tmp != root)) {
- if (tmp->type == XML_ELEMENT_NODE)
- break;
- if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
- break;
- tmp = tmp->next;
- }
- if (tmp == root) {
- ctxt->type = XSLT_OUTPUT_HTML;
- res->type = XML_HTML_DOCUMENT_NODE;
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
- res->intSubset = xmlCreateIntSubset(res, doctype,
- doctypePublic,
- doctypeSystem);
- #ifdef XSLT_GENERATE_HTML_DOCTYPE
- } else if (version != NULL) {
- xsltGetHTMLIDs(version, &doctypePublic,
- &doctypeSystem);
- if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
- res->intSubset =
- xmlCreateIntSubset(res, doctype,
- doctypePublic,
- doctypeSystem);
- #endif
- }
- }
- }
- if (ctxt->type == XSLT_OUTPUT_XML) {
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
- if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
- res->intSubset = xmlCreateIntSubset(res, doctype,
- doctypePublic,
- doctypeSystem);
- }
- }
- /*
- * Calls to redirect:write also take an optional attribute append.
- * Attribute append="true|yes" which will attempt to simply append
- * to an existing file instead of always opening a new file. The
- * default behavior of always overwriting the file still happens
- * if we do not specify append.
- * Note that append use will forbid use of remote URI target.
- */
- prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
- NULL);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *) "true") ||
- xmlStrEqual(prop, (const xmlChar *) "yes")) {
- style->omitXmlDeclaration = 1;
- redirect_write_append = 1;
- } else
- style->omitXmlDeclaration = 0;
- xmlFree(prop);
- }
- if (redirect_write_append) {
- FILE *f;
- f = fopen((const char *) filename, "ab");
- if (f == NULL) {
- ret = -1;
- } else {
- ret = xsltSaveResultToFile(f, res, style);
- fclose(f);
- }
- } else {
- ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
- }
- if (ret < 0) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: unable to save to %s\n",
- filename);
- #ifdef WITH_XSLT_DEBUG_EXTRA
- } else {
- xsltGenericDebug(xsltGenericDebugContext,
- "Wrote %d bytes to %s\n", ret, filename);
- #endif
- }
- error:
- ctxt->output = oldOutput;
- ctxt->insert = oldInsert;
- ctxt->type = oldType;
- ctxt->outputFile = oldOutputFile;
- if (URL != NULL)
- xmlFree(URL);
- if (filename != NULL)
- xmlFree(filename);
- if (style != NULL)
- xsltFreeStylesheet(style);
- if (res != NULL)
- xmlFreeDoc(res);
- }
- /************************************************************************
- * *
- * Most of the XSLT-1.0 transformations *
- * *
- ************************************************************************/
- /**
- * xsltSort:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt sort node
- * @comp: precomputed information
- *
- * function attached to xsl:sort nodes, but this should not be
- * called directly
- */
- void
- xsltSort(xsltTransformContextPtr ctxt,
- xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
- xsltElemPreCompPtr comp) {
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:sort : compilation failed\n");
- return;
- }
- xsltTransformError(ctxt, NULL, inst,
- "xsl:sort : improper use this should not be reached\n");
- }
- /**
- * xsltCopy:
- * @ctxt: an XSLT process context
- * @node: the node in the source tree
- * @inst: the element node of the XSLT-copy instruction
- * @castedComp: computed information of the XSLT-copy instruction
- *
- * Execute the XSLT-copy instruction on the source node.
- */
- void
- xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xmlNodePtr copy, oldInsert;
- oldInsert = ctxt->insert;
- if (ctxt->insert != NULL) {
- switch (node->type) {
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- /*
- * This text comes from the stylesheet
- * For stylesheets, the set of whitespace-preserving
- * element names consists of just xsl:text.
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (node->type == XML_CDATA_SECTION_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: CDATA text %s\n", node->content));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: text %s\n", node->content));
- }
- #endif
- xsltCopyText(ctxt, ctxt->insert, node, 0);
- break;
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- break;
- case XML_ELEMENT_NODE:
- /*
- * REVISIT NOTE: The "fake" is a doc-node, not an element node.
- * REMOVED:
- * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
- * return;
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: node %s\n", node->name));
- #endif
- copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
- ctxt->insert = copy;
- if (comp->use != NULL) {
- xsltApplyAttributeSet(ctxt, node, inst, comp->use);
- }
- break;
- case XML_ATTRIBUTE_NODE: {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: attribute %s\n", node->name));
- #endif
- /*
- * REVISIT: We could also raise an error if the parent is not
- * an element node.
- * OPTIMIZE TODO: Can we set the value/children of the
- * attribute without an intermediate copy of the string value?
- */
- xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
- break;
- }
- case XML_PI_NODE:
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: PI %s\n", node->name));
- #endif
- copy = xmlNewDocPI(ctxt->insert->doc, node->name,
- node->content);
- copy = xsltAddChild(ctxt->insert, copy);
- break;
- case XML_COMMENT_NODE:
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: comment\n"));
- #endif
- copy = xmlNewComment(node->content);
- copy = xsltAddChild(ctxt->insert, copy);
- break;
- case XML_NAMESPACE_DECL:
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopy: namespace declaration\n"));
- #endif
- xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
- break;
- default:
- break;
- }
- }
- switch (node->type) {
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_ELEMENT_NODE:
- xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
- NULL);
- break;
- default:
- break;
- }
- ctxt->insert = oldInsert;
- }
- /**
- * xsltText:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt text node
- * @comp: precomputed information
- *
- * Process the xslt text node on the source node
- */
- void
- xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
- xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
- if ((inst->children != NULL) && (comp != NULL)) {
- xmlNodePtr text = inst->children;
- xmlNodePtr copy;
- while (text != NULL) {
- if ((text->type != XML_TEXT_NODE) &&
- (text->type != XML_CDATA_SECTION_NODE)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:text content problem\n");
- break;
- }
- copy = xmlNewDocText(ctxt->output, text->content);
- if (text->type != XML_CDATA_SECTION_NODE) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Disable escaping: %s\n", text->content);
- #endif
- copy->name = xmlStringTextNoenc;
- }
- copy = xsltAddChild(ctxt->insert, copy);
- text = text->next;
- }
- }
- }
- /**
- * xsltElement:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt element node
- * @castedComp: precomputed information
- *
- * Process the xslt element node on the source node
- */
- void
- xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
- #ifdef XSLT_REFACTORED
- xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xmlChar *prop = NULL;
- const xmlChar *name, *prefix = NULL, *nsName = NULL;
- xmlNodePtr copy;
- xmlNodePtr oldInsert;
- if (ctxt->insert == NULL)
- return;
- /*
- * A comp->has_name == 0 indicates that we need to skip this instruction,
- * since it was evaluated to be invalid already during compilation.
- */
- if (!comp->has_name)
- return;
- /*
- * stack and saves
- */
- oldInsert = ctxt->insert;
- if (comp->name == NULL) {
- /* TODO: fix attr acquisition wrt to the XSLT namespace */
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "name", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element: The attribute 'name' is missing.\n");
- goto error;
- }
- if (xmlValidateQName(prop, 0)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element: The effective name '%s' is not a "
- "valid QName.\n", prop);
- /* we fall through to catch any further errors, if possible */
- }
- name = xsltSplitQName(ctxt->dict, prop, &prefix);
- xmlFree(prop);
- } else {
- /*
- * The "name" value was static.
- */
- #ifdef XSLT_REFACTORED
- prefix = comp->nsPrefix;
- name = comp->name;
- #else
- name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
- #endif
- }
- /*
- * Create the new element
- */
- if (ctxt->output->dict == ctxt->dict) {
- copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
- } else {
- copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
- }
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element : creation of %s failed\n", name);
- return;
- }
- copy = xsltAddChild(ctxt->insert, copy);
- if (copy == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element : xsltAddChild failed\n");
- return;
- }
- /*
- * Namespace
- * ---------
- */
- if (comp->has_ns) {
- if (comp->ns != NULL) {
- /*
- * No AVT; just plain text for the namespace name.
- */
- if (comp->ns[0] != 0)
- nsName = comp->ns;
- } else {
- xmlChar *tmpNsName;
- /*
- * Eval the AVT.
- */
- /* TODO: check attr acquisition wrt to the XSLT namespace */
- tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *) "namespace", XSLT_NAMESPACE);
- /*
- * SPEC XSLT 1.0:
- * "If the string is empty, then the expanded-name of the
- * attribute has a null namespace URI."
- */
- if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
- nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
- xmlFree(tmpNsName);
- }
- if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
- "forbidden.\n");
- goto error;
- }
- if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
- prefix = BAD_CAST "xml";
- } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
- prefix = NULL;
- }
- } else {
- xmlNsPtr ns;
- /*
- * SPEC XSLT 1.0:
- * "If the namespace attribute is not present, then the QName is
- * expanded into an expanded-name using the namespace declarations
- * in effect for the xsl:element element, including any default
- * namespace declaration.
- */
- ns = xmlSearchNs(inst->doc, inst, prefix);
- if (ns == NULL) {
- /*
- * TODO: Check this in the compilation layer in case it's a
- * static value.
- */
- if (prefix != NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element: The QName '%s:%s' has no "
- "namespace binding in scope in the stylesheet; "
- "this is an error, since the namespace was not "
- "specified by the instruction itself.\n", prefix, name);
- }
- } else
- nsName = ns->href;
- }
- /*
- * Find/create a matching ns-decl in the result tree.
- */
- if (nsName != NULL) {
- if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
- /* Don't use a prefix of "xmlns" */
- xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
- copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
- xmlFree(pref);
- } else {
- copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
- copy);
- }
- } else if ((copy->parent != NULL) &&
- (copy->parent->type == XML_ELEMENT_NODE) &&
- (copy->parent->ns != NULL))
- {
- /*
- * "Undeclare" the default namespace.
- */
- xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
- }
- ctxt->insert = copy;
- if (comp->has_use) {
- if (comp->use != NULL) {
- xsltApplyAttributeSet(ctxt, node, inst, comp->use);
- } else {
- xmlChar *attrSets = NULL;
- /*
- * BUG TODO: use-attribute-sets is not a value template.
- * use-attribute-sets = qnames
- */
- attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)"use-attribute-sets", NULL);
- if (attrSets != NULL) {
- xsltApplyAttributeSet(ctxt, node, inst, attrSets);
- xmlFree(attrSets);
- }
- }
- }
- /*
- * Instantiate the sequence constructor.
- */
- if (inst->children != NULL)
- xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
- NULL);
- error:
- ctxt->insert = oldInsert;
- return;
- }
- /**
- * xsltComment:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt comment node
- * @comp: precomputed information
- *
- * Process the xslt comment node on the source node
- */
- void
- xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
- xmlChar *value = NULL;
- xmlNodePtr commentNode;
- int len;
- value = xsltEvalTemplateString(ctxt, node, inst);
- /* TODO: use or generate the compiled form */
- len = xmlStrlen(value);
- if (len > 0) {
- if ((value[len-1] == '-') ||
- (xmlStrstr(value, BAD_CAST "--"))) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:comment : '--' or ending '-' not allowed in comment\n");
- /* fall through to try to catch further errors */
- }
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (value == NULL) {
- XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
- "xsltComment: empty\n"));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
- "xsltComment: content %s\n", value));
- }
- #endif
- commentNode = xmlNewComment(value);
- commentNode = xsltAddChild(ctxt->insert, commentNode);
- if (value != NULL)
- xmlFree(value);
- }
- /**
- * xsltProcessingInstruction:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt processing-instruction node
- * @castedComp: precomputed information
- *
- * Process the xslt processing-instruction node on the source node
- */
- void
- xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
- #ifdef XSLT_REFACTORED
- xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- const xmlChar *name;
- xmlChar *value = NULL;
- xmlNodePtr pi;
- if (ctxt->insert == NULL)
- return;
- if (comp->has_name == 0)
- return;
- if (comp->name == NULL) {
- name = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)"name", NULL);
- if (name == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:processing-instruction : name is missing\n");
- goto error;
- }
- } else {
- name = comp->name;
- }
- /* TODO: check that it's both an an NCName and a PITarget. */
- value = xsltEvalTemplateString(ctxt, node, inst);
- if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:processing-instruction: '?>' not allowed within PI content\n");
- goto error;
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (value == NULL) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessingInstruction: %s empty\n", name));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessingInstruction: %s content %s\n", name, value));
- }
- #endif
- pi = xmlNewDocPI(ctxt->insert->doc, name, value);
- pi = xsltAddChild(ctxt->insert, pi);
- error:
- if ((name != NULL) && (name != comp->name))
- xmlFree((xmlChar *) name);
- if (value != NULL)
- xmlFree(value);
- }
- /**
- * xsltCopyOf:
- * @ctxt: an XSLT transformation context
- * @node: the current node in the source tree
- * @inst: the element node of the XSLT copy-of instruction
- * @castedComp: precomputed information of the XSLT copy-of instruction
- *
- * Process the XSLT copy-of instruction.
- */
- void
- xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
- #ifdef XSLT_REFACTORED
- xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xmlXPathObjectPtr res = NULL;
- xmlNodeSetPtr list = NULL;
- int i;
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return;
- if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:copy-of : compilation failed\n");
- return;
- }
- /*
- * SPEC XSLT 1.0:
- * "The xsl:copy-of element can be used to insert a result tree
- * fragment into the result tree, without first converting it to
- * a string as xsl:value-of does (see [7.6.1 Generating Text with
- * xsl:value-of]). The required select attribute contains an
- * expression. When the result of evaluating the expression is a
- * result tree fragment, the complete fragment is copied into the
- * result tree. When the result is a node-set, all the nodes in the
- * set are copied in document order into the result tree; copying
- * an element node copies the attribute nodes, namespace nodes and
- * children of the element node as well as the element node itself;
- * a root node is copied by copying its children. When the result
- * is neither a node-set nor a result tree fragment, the result is
- * converted to a string and then inserted into the result tree,
- * as with xsl:value-of.
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyOf: select %s\n", comp->select));
- #endif
- /*
- * Evaluate the "select" expression.
- */
- res = xsltPreCompEval(ctxt, node, comp);
- if (res != NULL) {
- if (res->type == XPATH_NODESET) {
- /*
- * Node-set
- * --------
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyOf: result is a node set\n"));
- #endif
- list = res->nodesetval;
- if (list != NULL) {
- xmlNodePtr cur;
- /*
- * The list is already sorted in document order by XPath.
- * Append everything in this order under ctxt->insert.
- */
- for (i = 0;i < list->nodeNr;i++) {
- cur = list->nodeTab[i];
- if (cur == NULL)
- continue;
- if ((cur->type == XML_DOCUMENT_NODE) ||
- (cur->type == XML_HTML_DOCUMENT_NODE))
- {
- xsltCopyTreeList(ctxt, inst,
- cur->children, ctxt->insert, 0, 0);
- } else if (cur->type == XML_ATTRIBUTE_NODE) {
- xsltShallowCopyAttr(ctxt, inst,
- ctxt->insert, (xmlAttrPtr) cur);
- } else {
- xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
- }
- }
- }
- } else if (res->type == XPATH_XSLT_TREE) {
- /*
- * Result tree fragment
- * --------------------
- * E.g. via <xsl:variable ...><foo/></xsl:variable>
- * Note that the root node of such trees is an xmlDocPtr in Libxslt.
- */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyOf: result is a result tree fragment\n"));
- #endif
- list = res->nodesetval;
- if ((list != NULL) && (list->nodeTab != NULL) &&
- (list->nodeTab[0] != NULL) &&
- (IS_XSLT_REAL_NODE(list->nodeTab[0])))
- {
- xsltCopyTreeList(ctxt, inst,
- list->nodeTab[0]->children, ctxt->insert, 0, 0);
- }
- } else {
- xmlChar *value = NULL;
- /*
- * Convert to a string.
- */
- value = xmlXPathCastToString(res);
- if (value == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltCopyOf(): "
- "failed to cast an XPath object to string.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- } else {
- if (value[0] != 0) {
- /*
- * Append content as text node.
- */
- xsltCopyTextString(ctxt, ctxt->insert, value, 0);
- }
- xmlFree(value);
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyOf: result %s\n", res->stringval));
- #endif
- }
- }
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
- if (res != NULL)
- xmlXPathFreeObject(res);
- }
- /**
- * xsltValueOf:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt value-of node
- * @castedComp: precomputed information
- *
- * Process the xslt value-of node on the source node
- */
- void
- xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xmlXPathObjectPtr res = NULL;
- xmlChar *value = NULL;
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return;
- if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltValueOf(): "
- "The XSLT 'value-of' instruction was not compiled.\n");
- return;
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltValueOf: select %s\n", comp->select));
- #endif
- res = xsltPreCompEval(ctxt, node, comp);
- /*
- * Cast the XPath object to string.
- */
- if (res != NULL) {
- value = xmlXPathCastToString(res);
- if (value == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltValueOf(): "
- "failed to cast an XPath object to string.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- if (value[0] != 0) {
- xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
- }
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "XPath evaluation returned no result.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (value) {
- XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltValueOf: result '%s'\n", value));
- }
- #endif
- error:
- if (value != NULL)
- xmlFree(value);
- if (res != NULL)
- xmlXPathFreeObject(res);
- }
- /**
- * xsltNumber:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt number node
- * @castedComp: precomputed information
- *
- * Process the xslt number node on the source node
- */
- void
- xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xmlXPathContextPtr xpctxt;
- xmlNsPtr *oldXPNamespaces;
- int oldXPNsNr;
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:number : compilation failed\n");
- return;
- }
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
- return;
- comp->numdata.doc = inst->doc;
- comp->numdata.node = inst;
- xpctxt = ctxt->xpathCtxt;
- oldXPNsNr = xpctxt->nsNr;
- oldXPNamespaces = xpctxt->namespaces;
- #ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- xpctxt->namespaces = comp->inScopeNs->list;
- xpctxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- #else
- xpctxt->namespaces = comp->nsList;
- xpctxt->nsNr = comp->nsNr;
- #endif
- xsltNumberFormat(ctxt, &comp->numdata, node);
- xpctxt->nsNr = oldXPNsNr;
- xpctxt->namespaces = oldXPNamespaces;
- }
- /**
- * xsltApplyImports:
- * @ctxt: an XSLT transformation context
- * @contextNode: the current node in the source tree.
- * @inst: the element node of the XSLT 'apply-imports' instruction
- * @comp: the compiled instruction
- *
- * Process the XSLT apply-imports element.
- */
- void
- xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
- xmlNodePtr inst,
- xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
- {
- xsltTemplatePtr templ;
- if ((ctxt == NULL) || (inst == NULL))
- return;
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltApplyImports(): "
- "The XSLT 'apply-imports' instruction was not compiled.\n");
- return;
- }
- /*
- * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
- * same; the former is the "Current Template Rule" as defined by the
- * XSLT spec, the latter is simply the template struct being
- * currently processed.
- */
- if (ctxt->currentTemplateRule == NULL) {
- /*
- * SPEC XSLT 2.0:
- * "[ERR XTDE0560] It is a non-recoverable dynamic error if
- * xsl:apply-imports or xsl:next-match is evaluated when the
- * current template rule is null."
- */
- xsltTransformError(ctxt, NULL, inst,
- "It is an error to call 'apply-imports' "
- "when there's no current template rule.\n");
- return;
- }
- /*
- * TODO: Check if this is correct.
- */
- templ = xsltGetTemplate(ctxt, contextNode,
- ctxt->currentTemplateRule->style);
- if (templ != NULL) {
- xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
- /*
- * Set the current template rule.
- */
- ctxt->currentTemplateRule = templ;
- /*
- * URGENT TODO: Need xsl:with-param be handled somehow here?
- */
- xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
- templ, NULL);
- ctxt->currentTemplateRule = oldCurTemplRule;
- }
- else {
- /* Use built-in templates. */
- xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
- }
- }
- /**
- * xsltCallTemplate:
- * @ctxt: a XSLT transformation context
- * @node: the "current node" in the source tree
- * @inst: the XSLT 'call-template' instruction
- * @castedComp: the compiled information of the instruction
- *
- * Processes the XSLT call-template instruction on the source node.
- */
- void
- xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemCallTemplatePtr comp =
- (xsltStyleItemCallTemplatePtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- xsltStackElemPtr withParams = NULL;
- if (ctxt->insert == NULL)
- return;
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "The XSLT 'call-template' instruction was not compiled.\n");
- return;
- }
- /*
- * The template must have been precomputed
- */
- if (comp->templ == NULL) {
- comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
- if (comp->templ == NULL) {
- if (comp->ns != NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "The called template '{%s}%s' was not found.\n",
- comp->ns, comp->name);
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "The called template '%s' was not found.\n",
- comp->name);
- }
- return;
- }
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if ((comp != NULL) && (comp->name != NULL))
- XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "call-template: name %s\n", comp->name));
- #endif
- if (inst->children) {
- xmlNodePtr cur;
- xsltStackElemPtr param;
- cur = inst->children;
- while (cur != NULL) {
- #ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(cur, node, comp->templ, ctxt);
- #endif
- if (ctxt->state == XSLT_STATE_STOPPED) break;
- /*
- * TODO: The "with-param"s could be part of the "call-template"
- * structure. Avoid to "search" for params dynamically
- * in the XML tree every time.
- */
- if (IS_XSLT_ELEM(cur)) {
- if (IS_XSLT_NAME(cur, "with-param")) {
- param = xsltParseStylesheetCallerParam(ctxt, cur);
- if (param != NULL) {
- param->next = withParams;
- withParams = param;
- }
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:call-template: misplaced xsl:%s\n", cur->name);
- }
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:call-template: misplaced %s element\n", cur->name);
- }
- cur = cur->next;
- }
- }
- /*
- * Create a new frame using the params first
- */
- xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
- withParams);
- if (withParams != NULL)
- xsltFreeStackElemList(withParams);
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if ((comp != NULL) && (comp->name != NULL))
- XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "call-template returned: name %s\n", comp->name));
- #endif
- }
- /**
- * xsltApplyTemplates:
- * @ctxt: a XSLT transformation context
- * @node: the 'current node' in the source tree
- * @inst: the element node of an XSLT 'apply-templates' instruction
- * @castedComp: the compiled instruction
- *
- * Processes the XSLT 'apply-templates' instruction on the current node.
- */
- void
- xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemApplyTemplatesPtr comp =
- (xsltStyleItemApplyTemplatesPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- int i;
- xmlNodePtr cur, oldContextNode;
- xmlNodeSetPtr list = NULL, oldList;
- xsltStackElemPtr withParams = NULL;
- int oldXPProximityPosition, oldXPContextSize;
- const xmlChar *oldMode, *oldModeURI;
- xmlDocPtr oldXPDoc;
- xsltDocumentPtr oldDocInfo;
- xmlXPathContextPtr xpctxt;
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:apply-templates : compilation failed\n");
- return;
- }
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
- return;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if ((node != NULL) && (node->name != NULL))
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: node: '%s'\n", node->name));
- #endif
- xpctxt = ctxt->xpathCtxt;
- /*
- * Save context states.
- */
- oldContextNode = ctxt->node;
- oldMode = ctxt->mode;
- oldModeURI = ctxt->modeURI;
- oldDocInfo = ctxt->document;
- oldList = ctxt->nodeList;
- /*
- * The xpath context size and proximity position, as
- * well as the xpath and context documents, may be changed
- * so we save their initial state and will restore on exit
- */
- oldXPContextSize = xpctxt->contextSize;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPDoc = xpctxt->doc;
- /*
- * Set up contexts.
- */
- ctxt->mode = comp->mode;
- ctxt->modeURI = comp->modeURI;
- if (comp->select != NULL) {
- xmlXPathObjectPtr res = NULL;
- if (comp->comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:apply-templates : compilation failed\n");
- goto error;
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: select %s\n", comp->select));
- #endif
- res = xsltPreCompEval(ctxt, node, comp);
- if (res != NULL) {
- if (res->type == XPATH_NODESET) {
- list = res->nodesetval; /* consume the node set */
- res->nodesetval = NULL;
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "The 'select' expression did not evaluate to a "
- "node set.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- xmlXPathFreeObject(res);
- goto error;
- }
- xmlXPathFreeObject(res);
- /*
- * Note: An xsl:apply-templates with a 'select' attribute,
- * can change the current source doc.
- */
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "Failed to evaluate the 'select' expression.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- if (list == NULL) {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: select didn't evaluate to a node list\n"));
- #endif
- goto exit;
- }
- /*
- *
- * NOTE: Previously a document info (xsltDocument) was
- * created and attached to the Result Tree Fragment.
- * But such a document info is created on demand in
- * xsltKeyFunction() (functions.c), so we need to create
- * it here beforehand.
- * In order to take care of potential keys we need to
- * do some extra work for the case when a Result Tree Fragment
- * is converted into a nodeset (e.g. exslt:node-set()) :
- * We attach a "pseudo-doc" (xsltDocument) to _private.
- * This xsltDocument, together with the keyset, will be freed
- * when the Result Tree Fragment is freed.
- *
- */
- #if 0
- if ((ctxt->nbKeys > 0) &&
- (list->nodeNr != 0) &&
- (list->nodeTab[0]->doc != NULL) &&
- XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
- {
- /*
- * NOTE that it's also OK if @effectiveDocInfo will be
- * set to NULL.
- */
- isRTF = 1;
- effectiveDocInfo = list->nodeTab[0]->doc->_private;
- }
- #endif
- } else {
- /*
- * Build an XPath node set with the children
- */
- list = xmlXPathNodeSetCreate(NULL);
- if (list == NULL)
- goto error;
- if (node->type != XML_NAMESPACE_DECL)
- cur = node->children;
- else
- cur = NULL;
- while (cur != NULL) {
- if (IS_XSLT_REAL_NODE(cur))
- xmlXPathNodeSetAddUnique(list, cur);
- cur = cur->next;
- }
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- if (list != NULL)
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
- #endif
- if ((list == NULL) || (list->nodeNr == 0))
- goto exit;
- /*
- * Set the context's node set and size; this is also needed for
- * for xsltDoSortFunction().
- */
- ctxt->nodeList = list;
- /*
- * Process xsl:with-param and xsl:sort instructions.
- * (The code became so verbose just to avoid the
- * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
- * BUG TODO: We are not using namespaced potentially defined on the
- * xsl:sort or xsl:with-param elements; XPath expression might fail.
- */
- if (inst->children) {
- xsltStackElemPtr param;
- cur = inst->children;
- while (cur) {
- #ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(cur, node, NULL, ctxt);
- #endif
- if (ctxt->state == XSLT_STATE_STOPPED)
- break;
- if (cur->type == XML_TEXT_NODE) {
- cur = cur->next;
- continue;
- }
- if (! IS_XSLT_ELEM(cur))
- break;
- if (IS_XSLT_NAME(cur, "with-param")) {
- param = xsltParseStylesheetCallerParam(ctxt, cur);
- if (param != NULL) {
- param->next = withParams;
- withParams = param;
- }
- }
- if (IS_XSLT_NAME(cur, "sort")) {
- xsltTemplatePtr oldCurTempRule =
- ctxt->currentTemplateRule;
- int nbsorts = 0;
- xmlNodePtr sorts[XSLT_MAX_SORT];
- sorts[nbsorts++] = cur;
- cur = cur->next;
- while (cur) {
- #ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(cur, node, NULL, ctxt);
- #endif
- if (ctxt->state == XSLT_STATE_STOPPED)
- break;
- if (cur->type == XML_TEXT_NODE) {
- cur = cur->next;
- continue;
- }
- if (! IS_XSLT_ELEM(cur))
- break;
- if (IS_XSLT_NAME(cur, "with-param")) {
- param = xsltParseStylesheetCallerParam(ctxt, cur);
- if (param != NULL) {
- param->next = withParams;
- withParams = param;
- }
- }
- if (IS_XSLT_NAME(cur, "sort")) {
- if (nbsorts >= XSLT_MAX_SORT) {
- xsltTransformError(ctxt, NULL, cur,
- "The number (%d) of xsl:sort instructions exceeds the "
- "maximum allowed by this processor's settings.\n",
- nbsorts);
- ctxt->state = XSLT_STATE_STOPPED;
- break;
- } else {
- sorts[nbsorts++] = cur;
- }
- }
- cur = cur->next;
- }
- /*
- * The "current template rule" is cleared for xsl:sort.
- */
- ctxt->currentTemplateRule = NULL;
- /*
- * Sort.
- */
- xsltDoSortFunction(ctxt, sorts, nbsorts);
- ctxt->currentTemplateRule = oldCurTempRule;
- break;
- }
- cur = cur->next;
- }
- }
- xpctxt->contextSize = list->nodeNr;
- /*
- * Apply templates for all selected source nodes.
- */
- for (i = 0; i < list->nodeNr; i++) {
- cur = list->nodeTab[i];
- /*
- * The node becomes the "current node".
- */
- ctxt->node = cur;
- /*
- * An xsl:apply-templates can change the current context doc.
- * OPTIMIZE TODO: Get rid of the need to set the context doc.
- */
- if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
- xpctxt->doc = cur->doc;
- xpctxt->proximityPosition = i + 1;
- /*
- * Find and apply a template for this node.
- */
- xsltProcessOneNode(ctxt, cur, withParams);
- }
- exit:
- error:
- /*
- * Free the parameter list.
- */
- if (withParams != NULL)
- xsltFreeStackElemList(withParams);
- if (list != NULL)
- xmlXPathFreeNodeSet(list);
- /*
- * Restore context states.
- */
- xpctxt->doc = oldXPDoc;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->proximityPosition = oldXPProximityPosition;
- ctxt->document = oldDocInfo;
- ctxt->nodeList = oldList;
- ctxt->node = oldContextNode;
- ctxt->mode = oldMode;
- ctxt->modeURI = oldModeURI;
- }
- /**
- * xsltChoose:
- * @ctxt: a XSLT process context
- * @contextNode: the current node in the source tree
- * @inst: the xsl:choose instruction
- * @comp: compiled information of the instruction
- *
- * Processes the xsl:choose instruction on the source node.
- */
- void
- xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
- xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
- {
- xmlNodePtr cur;
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
- return;
- /*
- * TODO: Content model checks should be done only at compilation
- * time.
- */
- cur = inst->children;
- if (cur == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:choose: The instruction has no content.\n");
- return;
- }
- #ifdef XSLT_REFACTORED
- /*
- * We don't check the content model during transformation.
- */
- #else
- if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:choose: xsl:when expected first\n");
- return;
- }
- #endif
- {
- int testRes = 0, res = 0;
- #ifdef XSLT_REFACTORED
- xsltStyleItemWhenPtr wcomp = NULL;
- #else
- xsltStylePreCompPtr wcomp = NULL;
- #endif
- /*
- * Process xsl:when ---------------------------------------------------
- */
- while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
- wcomp = cur->psvi;
- if ((wcomp == NULL) || (wcomp->test == NULL) ||
- (wcomp->comp == NULL))
- {
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in xsltChoose(): "
- "The XSLT 'when' instruction was not compiled.\n");
- goto error;
- }
- #ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE) {
- /*
- * TODO: Isn't comp->templ always NULL for xsl:choose?
- */
- xslHandleDebugger(cur, contextNode, NULL, ctxt);
- }
- #endif
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltChoose: test %s\n", wcomp->test));
- #endif
- #ifdef XSLT_FAST_IF
- res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
- if (res == -1) {
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- testRes = (res == 1) ? 1 : 0;
- #else /* XSLT_FAST_IF */
- res = xsltPreCompEval(ctxt, cotextNode, wcomp);
- if (res != NULL) {
- if (res->type != XPATH_BOOLEAN)
- res = xmlXPathConvertBoolean(res);
- if (res->type == XPATH_BOOLEAN)
- testRes = res->boolval;
- else {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltChoose: test didn't evaluate to a boolean\n"));
- #endif
- goto error;
- }
- xmlXPathFreeObject(res);
- res = NULL;
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- #endif /* else of XSLT_FAST_IF */
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltChoose: test evaluate to %d\n", testRes));
- #endif
- if (testRes)
- goto test_is_true;
- cur = cur->next;
- }
- /*
- * Process xsl:otherwise ----------------------------------------------
- */
- if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
- #ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(cur, contextNode, NULL, ctxt);
- #endif
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "evaluating xsl:otherwise\n"));
- #endif
- goto test_is_true;
- }
- goto exit;
- test_is_true:
- goto process_sequence;
- }
- process_sequence:
- /*
- * Instantiate the sequence constructor.
- */
- xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
- NULL);
- exit:
- error:
- return;
- }
- /**
- * xsltIf:
- * @ctxt: a XSLT process context
- * @contextNode: the current node in the source tree
- * @inst: the xsl:if instruction
- * @castedComp: compiled information of the instruction
- *
- * Processes the xsl:if instruction on the source node.
- */
- void
- xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- int res = 0;
- #ifdef XSLT_REFACTORED
- xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
- return;
- if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltIf(): "
- "The XSLT 'if' instruction was not compiled.\n");
- return;
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test %s\n", comp->test));
- #endif
- #ifdef XSLT_FAST_IF
- {
- xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
- res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp);
- /*
- * Cleanup fragments created during evaluation of the
- * "select" expression.
- */
- if (oldLocalFragmentTop != ctxt->localRVT)
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
- }
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test evaluate to %d\n", res));
- #endif
- if (res == -1) {
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- if (res == 1) {
- /*
- * Instantiate the sequence constructor of xsl:if.
- */
- xsltApplySequenceConstructor(ctxt,
- contextNode, inst->children, NULL);
- }
- #else /* XSLT_FAST_IF */
- {
- /*
- * OLD CODE:
- */
- xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp);
- if (xpobj != NULL) {
- if (xpobj->type != XPATH_BOOLEAN)
- xpobj = xmlXPathConvertBoolean(xpobj);
- if (xpobj->type == XPATH_BOOLEAN) {
- res = xpobj->boolval;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test evaluate to %d\n", res));
- #endif
- if (res) {
- xsltApplySequenceConstructor(ctxt,
- contextNode, inst->children, NULL);
- }
- } else {
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt, XSLT_TRACE_IF,
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test didn't evaluate to a boolean\n"));
- #endif
- ctxt->state = XSLT_STATE_STOPPED;
- }
- xmlXPathFreeObject(xpobj);
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
- }
- #endif /* else of XSLT_FAST_IF */
- error:
- return;
- }
- /**
- * xsltForEach:
- * @ctxt: an XSLT transformation context
- * @contextNode: the "current node" in the source tree
- * @inst: the element node of the xsl:for-each instruction
- * @castedComp: the compiled information of the instruction
- *
- * Process the xslt for-each node on the source node
- */
- void
- xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
- xmlNodePtr inst, xsltElemPreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
- #else
- xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
- #endif
- int i;
- xmlXPathObjectPtr res = NULL;
- xmlNodePtr cur, curInst;
- xmlNodeSetPtr list = NULL;
- xmlNodeSetPtr oldList;
- int oldXPProximityPosition, oldXPContextSize;
- xmlNodePtr oldContextNode;
- xsltTemplatePtr oldCurTemplRule;
- xmlDocPtr oldXPDoc;
- xsltDocumentPtr oldDocInfo;
- xmlXPathContextPtr xpctxt;
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltForEach(): Bad arguments.\n");
- return;
- }
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltForEach(): "
- "The XSLT 'for-each' instruction was not compiled.\n");
- return;
- }
- if ((comp->select == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltForEach(): "
- "The selecting expression of the XSLT 'for-each' "
- "instruction was not compiled correctly.\n");
- return;
- }
- xpctxt = ctxt->xpathCtxt;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: select %s\n", comp->select));
- #endif
- /*
- * Save context states.
- */
- oldDocInfo = ctxt->document;
- oldList = ctxt->nodeList;
- oldContextNode = ctxt->node;
- /*
- * The "current template rule" is cleared for the instantiation of
- * xsl:for-each.
- */
- oldCurTemplRule = ctxt->currentTemplateRule;
- ctxt->currentTemplateRule = NULL;
- oldXPDoc = xpctxt->doc;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPContextSize = xpctxt->contextSize;
- /*
- * Evaluate the 'select' expression.
- */
- res = xsltPreCompEval(ctxt, contextNode, comp);
- if (res != NULL) {
- if (res->type == XPATH_NODESET)
- list = res->nodesetval;
- else {
- xsltTransformError(ctxt, NULL, inst,
- "The 'select' expression does not evaluate to a node set.\n");
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: select didn't evaluate to a node list\n"));
- #endif
- goto error;
- }
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "Failed to evaluate the 'select' expression.\n");
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- if ((list == NULL) || (list->nodeNr <= 0))
- goto exit;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
- #endif
- /*
- * Set the list; this has to be done already here for xsltDoSortFunction().
- */
- ctxt->nodeList = list;
- /*
- * Handle xsl:sort instructions and skip them for further processing.
- * BUG TODO: We are not using namespaced potentially defined on the
- * xsl:sort element; XPath expression might fail.
- */
- curInst = inst->children;
- if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
- int nbsorts = 0;
- xmlNodePtr sorts[XSLT_MAX_SORT];
- sorts[nbsorts++] = curInst;
- #ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(curInst, contextNode, NULL, ctxt);
- #endif
- curInst = curInst->next;
- while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
- if (nbsorts >= XSLT_MAX_SORT) {
- xsltTransformError(ctxt, NULL, curInst,
- "The number of xsl:sort instructions exceeds the "
- "maximum (%d) allowed by this processor.\n",
- XSLT_MAX_SORT);
- goto error;
- } else {
- sorts[nbsorts++] = curInst;
- }
- #ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(curInst, contextNode, NULL, ctxt);
- #endif
- curInst = curInst->next;
- }
- xsltDoSortFunction(ctxt, sorts, nbsorts);
- }
- xpctxt->contextSize = list->nodeNr;
- /*
- * Instantiate the sequence constructor for each selected node.
- */
- for (i = 0; i < list->nodeNr; i++) {
- cur = list->nodeTab[i];
- /*
- * The selected node becomes the "current node".
- */
- ctxt->node = cur;
- /*
- * An xsl:for-each can change the current context doc.
- * OPTIMIZE TODO: Get rid of the need to set the context doc.
- */
- if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
- xpctxt->doc = cur->doc;
- xpctxt->proximityPosition = i + 1;
- xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
- }
- exit:
- error:
- if (res != NULL)
- xmlXPathFreeObject(res);
- /*
- * Restore old states.
- */
- ctxt->document = oldDocInfo;
- ctxt->nodeList = oldList;
- ctxt->node = oldContextNode;
- ctxt->currentTemplateRule = oldCurTemplRule;
- xpctxt->doc = oldXPDoc;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->proximityPosition = oldXPProximityPosition;
- }
- /************************************************************************
- * *
- * Generic interface *
- * *
- ************************************************************************/
- #ifdef XSLT_GENERATE_HTML_DOCTYPE
- typedef struct xsltHTMLVersion {
- const char *version;
- const char *public;
- const char *system;
- } xsltHTMLVersion;
- static xsltHTMLVersion xsltHTMLVersions[] = {
- { "5", NULL, "about:legacy-compat" },
- { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
- "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
- { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
- "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
- { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
- "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
- { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
- "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
- { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
- "http://www.w3.org/TR/html4/strict.dtd"},
- { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
- "http://www.w3.org/TR/html4/loose.dtd"},
- { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
- "http://www.w3.org/TR/html4/frameset.dtd"},
- { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
- "http://www.w3.org/TR/html4/loose.dtd"},
- { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
- };
- /**
- * xsltGetHTMLIDs:
- * @version: the version string
- * @publicID: used to return the public ID
- * @systemID: used to return the system ID
- *
- * Returns -1 if not found, 0 otherwise and the system and public
- * Identifier for this given verion of HTML
- */
- static int
- xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
- const xmlChar **systemID) {
- unsigned int i;
- if (version == NULL)
- return(-1);
- for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
- i++) {
- if (!xmlStrcasecmp(version,
- (const xmlChar *) xsltHTMLVersions[i].version)) {
- if (publicID != NULL)
- *publicID = (const xmlChar *) xsltHTMLVersions[i].public;
- if (systemID != NULL)
- *systemID = (const xmlChar *) xsltHTMLVersions[i].system;
- return(0);
- }
- }
- return(-1);
- }
- #endif
- /**
- * xsltApplyStripSpaces:
- * @ctxt: a XSLT process context
- * @node: the root of the XML tree
- *
- * Strip the unwanted ignorable spaces from the input tree
- */
- void
- xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
- xmlNodePtr current;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- int nb = 0;
- #endif
- current = node;
- while (current != NULL) {
- /*
- * Cleanup children empty nodes if asked for
- */
- if ((IS_XSLT_REAL_NODE(current)) &&
- (current->children != NULL) &&
- (xsltFindElemSpaceHandling(ctxt, current))) {
- xmlNodePtr delete = NULL, cur = current->children;
- while (cur != NULL) {
- if (IS_BLANK_NODE(cur))
- delete = cur;
- cur = cur->next;
- if (delete != NULL) {
- xmlUnlinkNode(delete);
- xmlFreeNode(delete);
- delete = NULL;
- #ifdef WITH_XSLT_DEBUG_PROCESS
- nb++;
- #endif
- }
- }
- }
- /*
- * Skip to next node in document order.
- */
- if (node->type == XML_ENTITY_REF_NODE) {
- /* process deep in entities */
- xsltApplyStripSpaces(ctxt, node->children);
- }
- if ((current->children != NULL) &&
- (current->type != XML_ENTITY_REF_NODE)) {
- current = current->children;
- } else if (current->next != NULL) {
- current = current->next;
- } else {
- do {
- current = current->parent;
- if (current == NULL)
- break;
- if (current == node)
- goto done;
- if (current->next != NULL) {
- current = current->next;
- break;
- }
- } while (current != NULL);
- }
- }
- done:
- #ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
- #endif
- return;
- }
- static int
- xsltCountKeys(xsltTransformContextPtr ctxt)
- {
- xsltStylesheetPtr style;
- xsltKeyDefPtr keyd;
- if (ctxt == NULL)
- return(-1);
- /*
- * Do we have those nastly templates with a key() in the match pattern?
- */
- ctxt->hasTemplKeyPatterns = 0;
- style = ctxt->style;
- while (style != NULL) {
- if (style->keyMatch != NULL) {
- ctxt->hasTemplKeyPatterns = 1;
- break;
- }
- style = xsltNextImport(style);
- }
- /*
- * Count number of key declarations.
- */
- ctxt->nbKeys = 0;
- style = ctxt->style;
- while (style != NULL) {
- keyd = style->keys;
- while (keyd) {
- ctxt->nbKeys++;
- keyd = keyd->next;
- }
- style = xsltNextImport(style);
- }
- return(ctxt->nbKeys);
- }
- /**
- * xsltApplyStylesheetInternal:
- * @style: a parsed XSLT stylesheet
- * @doc: a parsed XML document
- * @params: a NULL terminated array of parameters names/values tuples
- * @output: the targetted output
- * @profile: profile FILE * output or NULL
- * @user: user provided parameter
- *
- * Apply the stylesheet to the document
- * NOTE: This may lead to a non-wellformed output XML wise !
- *
- * Returns the result document or NULL in case of error
- */
- static xmlDocPtr
- xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
- const char **params, const char *output,
- FILE * profile, xsltTransformContextPtr userCtxt)
- {
- xmlDocPtr res = NULL;
- xsltTransformContextPtr ctxt = NULL;
- xmlNodePtr root, node;
- const xmlChar *method;
- const xmlChar *doctypePublic;
- const xmlChar *doctypeSystem;
- const xmlChar *version;
- const xmlChar *encoding;
- xsltStackElemPtr variables;
- xsltStackElemPtr vptr;
- xsltInitGlobals();
- if ((style == NULL) || (doc == NULL))
- return (NULL);
- if (style->internalized == 0) {
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "Stylesheet was not fully internalized !\n");
- #endif
- }
- if (doc->intSubset != NULL) {
- /*
- * Avoid hitting the DTD when scanning nodes
- * but keep it linked as doc->intSubset
- */
- xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
- if (cur->next != NULL)
- cur->next->prev = cur->prev;
- if (cur->prev != NULL)
- cur->prev->next = cur->next;
- if (doc->children == cur)
- doc->children = cur->next;
- if (doc->last == cur)
- doc->last = cur->prev;
- cur->prev = cur->next = NULL;
- }
- /*
- * Check for XPath document order availability
- */
- root = xmlDocGetRootElement(doc);
- if (root != NULL) {
- if (((ptrdiff_t) root->content >= 0) &&
- (xslDebugStatus == XSLT_DEBUG_NONE))
- xmlXPathOrderDocElems(doc);
- }
- if (userCtxt != NULL)
- ctxt = userCtxt;
- else
- ctxt = xsltNewTransformContext(style, doc);
- if (ctxt == NULL)
- return (NULL);
- ctxt->initialContextDoc = doc;
- ctxt->initialContextNode = (xmlNodePtr) doc;
- if (profile != NULL) {
- #ifdef WITH_PROFILER
- ctxt->profile = 1;
- #else
- xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
- "xsltApplyStylesheetInternal: "
- "libxslt compiled without profiler\n");
- goto error;
- #endif
- }
- if (output != NULL)
- ctxt->outputFile = output;
- else
- ctxt->outputFile = NULL;
- /*
- * internalize the modes if needed
- */
- if (ctxt->dict != NULL) {
- if (ctxt->mode != NULL)
- ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
- if (ctxt->modeURI != NULL)
- ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
- }
- XSLT_GET_IMPORT_PTR(method, style, method)
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
- XSLT_GET_IMPORT_PTR(version, style, version)
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- if ((method != NULL) &&
- (!xmlStrEqual(method, (const xmlChar *) "xml")))
- {
- if (xmlStrEqual(method, (const xmlChar *) "html")) {
- ctxt->type = XSLT_OUTPUT_HTML;
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
- res = htmlNewDoc(doctypeSystem, doctypePublic);
- } else {
- if (version == NULL) {
- xmlDtdPtr dtd;
- res = htmlNewDoc(NULL, NULL);
- /*
- * Make sure no DTD node is generated in this case
- */
- if (res != NULL) {
- dtd = xmlGetIntSubset(res);
- if (dtd != NULL) {
- xmlUnlinkNode((xmlNodePtr) dtd);
- xmlFreeDtd(dtd);
- }
- res->intSubset = NULL;
- res->extSubset = NULL;
- }
- } else {
- #ifdef XSLT_GENERATE_HTML_DOCTYPE
- xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
- #endif
- res = htmlNewDoc(doctypeSystem, doctypePublic);
- }
- }
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for output\n");
- #endif
- } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
- xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
- "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
- ctxt->type = XSLT_OUTPUT_HTML;
- res = htmlNewDoc(doctypeSystem, doctypePublic);
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for output\n");
- #endif
- } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
- ctxt->type = XSLT_OUTPUT_TEXT;
- res = xmlNewDoc(style->version);
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(res->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for output\n");
- #endif
- } else {
- xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
- "xsltApplyStylesheetInternal: unsupported method (%s)\n",
- method);
- goto error;
- }
- } else {
- ctxt->type = XSLT_OUTPUT_XML;
- res = xmlNewDoc(style->version);
- if (res == NULL)
- goto error;
- res->dict = ctxt->dict;
- xmlDictReference(ctxt->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for output\n");
- #endif
- }
- res->charset = XML_CHAR_ENCODING_UTF8;
- if (encoding != NULL)
- res->encoding = xmlStrdup(encoding);
- variables = style->variables;
- ctxt->node = (xmlNodePtr) doc;
- ctxt->output = res;
- ctxt->xpathCtxt->contextSize = 1;
- ctxt->xpathCtxt->proximityPosition = 1;
- ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
- /*
- * Start the evaluation, evaluate the params, the stylesheets globals
- * and start by processing the top node.
- */
- if (xsltNeedElemSpaceHandling(ctxt))
- xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
- /*
- * Evaluate global params and user-provided params.
- */
- if (ctxt->globalVars == NULL)
- ctxt->globalVars = xmlHashCreate(20);
- if (params != NULL) {
- xsltEvalUserParams(ctxt, params);
- }
- /* need to be called before evaluating global variables */
- xsltCountKeys(ctxt);
- xsltEvalGlobalVariables(ctxt);
- /* Clean up any unused RVTs. */
- xsltReleaseLocalRVTs(ctxt, NULL);
- ctxt->insert = (xmlNodePtr) res;
- ctxt->varsBase = ctxt->varsNr - 1;
- /*
- * Start processing the source tree -----------------------------------
- */
- xsltProcessOneNode(ctxt, ctxt->node, NULL);
- /*
- * Remove all remaining vars from the stack.
- */
- xsltLocalVariablePop(ctxt, 0, -2);
- xsltShutdownCtxtExts(ctxt);
- xsltCleanupTemplates(style); /* TODO: <- style should be read only */
- /*
- * Now cleanup our variables so stylesheet can be re-used
- *
- * TODO: this is not needed anymore global variables are copied
- * and not evaluated directly anymore, keep this as a check
- */
- if (style->variables != variables) {
- vptr = style->variables;
- while (vptr->next != variables)
- vptr = vptr->next;
- vptr->next = NULL;
- xsltFreeStackElemList(style->variables);
- style->variables = variables;
- }
- vptr = style->variables;
- while (vptr != NULL) {
- if (vptr->computed) {
- if (vptr->value != NULL) {
- xmlXPathFreeObject(vptr->value);
- vptr->value = NULL;
- vptr->computed = 0;
- }
- }
- vptr = vptr->next;
- }
- #if 0
- /*
- * code disabled by wmb; awaiting kb's review
- * problem is that global variable(s) may contain xpath objects
- * from doc associated with RVT, so can't be freed at this point.
- * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
- * I assume this shouldn't be required at this point.
- */
- /*
- * Free all remaining tree fragments.
- */
- xsltFreeRVTs(ctxt);
- #endif
- /*
- * Do some post processing work depending on the generated output
- */
- root = xmlDocGetRootElement(res);
- if (root != NULL) {
- const xmlChar *doctype = NULL;
- if ((root->ns != NULL) && (root->ns->prefix != NULL))
- doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
- if (doctype == NULL)
- doctype = root->name;
- /*
- * Apply the default selection of the method
- */
- if ((method == NULL) &&
- (root->ns == NULL) &&
- (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
- xmlNodePtr tmp;
- tmp = res->children;
- while ((tmp != NULL) && (tmp != root)) {
- if (tmp->type == XML_ELEMENT_NODE)
- break;
- if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
- break;
- tmp = tmp->next;
- }
- if (tmp == root) {
- ctxt->type = XSLT_OUTPUT_HTML;
- /*
- * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
- * transformation on the doc, but functions like
- */
- res->type = XML_HTML_DOCUMENT_NODE;
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
- res->intSubset = xmlCreateIntSubset(res, doctype,
- doctypePublic,
- doctypeSystem);
- #ifdef XSLT_GENERATE_HTML_DOCTYPE
- } else if (version != NULL) {
- xsltGetHTMLIDs(version, &doctypePublic,
- &doctypeSystem);
- if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
- res->intSubset =
- xmlCreateIntSubset(res, doctype,
- doctypePublic,
- doctypeSystem);
- #endif
- }
- }
- }
- if (ctxt->type == XSLT_OUTPUT_XML) {
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
- xmlNodePtr last;
- /* Need a small "hack" here to assure DTD comes before
- possible comment nodes */
- node = res->children;
- last = res->last;
- res->children = NULL;
- res->last = NULL;
- res->intSubset = xmlCreateIntSubset(res, doctype,
- doctypePublic,
- doctypeSystem);
- if (res->children != NULL) {
- res->children->next = node;
- node->prev = res->children;
- res->last = last;
- } else {
- res->children = node;
- res->last = last;
- }
- }
- }
- }
- xmlXPathFreeNodeSet(ctxt->nodeList);
- #ifdef WITH_PROFILER
- if (profile != NULL) {
- xsltSaveProfiling(ctxt, profile);
- }
- #endif
- /*
- * Be pedantic.
- */
- if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
- xmlFreeDoc(res);
- res = NULL;
- }
- if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
- int ret;
- ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
- if (ret == 0) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltApplyStylesheet: forbidden to save to %s\n",
- output);
- } else if (ret < 0) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltApplyStylesheet: saving to %s may not be possible\n",
- output);
- }
- }
- #ifdef XSLT_DEBUG_PROFILE_CACHE
- printf("# Cache:\n");
- printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
- printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);
- #endif
- if ((ctxt != NULL) && (userCtxt == NULL))
- xsltFreeTransformContext(ctxt);
- return (res);
- error:
- if (res != NULL)
- xmlFreeDoc(res);
- #ifdef XSLT_DEBUG_PROFILE_CACHE
- printf("# Cache:\n");
- printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
- printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);
- #endif
- if ((ctxt != NULL) && (userCtxt == NULL))
- xsltFreeTransformContext(ctxt);
- return (NULL);
- }
- /**
- * xsltApplyStylesheet:
- * @style: a parsed XSLT stylesheet
- * @doc: a parsed XML document
- * @params: a NULL terminated arry of parameters names/values tuples
- *
- * Apply the stylesheet to the document
- * NOTE: This may lead to a non-wellformed output XML wise !
- *
- * Returns the result document or NULL in case of error
- */
- xmlDocPtr
- xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
- const char **params)
- {
- return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
- }
- /**
- * xsltProfileStylesheet:
- * @style: a parsed XSLT stylesheet
- * @doc: a parsed XML document
- * @params: a NULL terminated arry of parameters names/values tuples
- * @output: a FILE * for the profiling output
- *
- * Apply the stylesheet to the document and dump the profiling to
- * the given output.
- *
- * Returns the result document or NULL in case of error
- */
- xmlDocPtr
- xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
- const char **params, FILE * output)
- {
- xmlDocPtr res;
- res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
- return (res);
- }
- /**
- * xsltApplyStylesheetUser:
- * @style: a parsed XSLT stylesheet
- * @doc: a parsed XML document
- * @params: a NULL terminated array of parameters names/values tuples
- * @output: the targetted output
- * @profile: profile FILE * output or NULL
- * @userCtxt: user provided transform context
- *
- * Apply the stylesheet to the document and allow the user to provide
- * its own transformation context.
- *
- * Returns the result document or NULL in case of error
- */
- xmlDocPtr
- xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
- const char **params, const char *output,
- FILE * profile, xsltTransformContextPtr userCtxt)
- {
- xmlDocPtr res;
- res = xsltApplyStylesheetInternal(style, doc, params, output,
- profile, userCtxt);
- return (res);
- }
- /**
- * xsltRunStylesheetUser:
- * @style: a parsed XSLT stylesheet
- * @doc: a parsed XML document
- * @params: a NULL terminated array of parameters names/values tuples
- * @output: the URL/filename ot the generated resource if available
- * @SAX: a SAX handler for progressive callback output (not implemented yet)
- * @IObuf: an output buffer for progressive output (not implemented yet)
- * @profile: profile FILE * output or NULL
- * @userCtxt: user provided transform context
- *
- * Apply the stylesheet to the document and generate the output according
- * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
- *
- * NOTE: This may lead to a non-wellformed output XML wise !
- * NOTE: This may also result in multiple files being generated
- * NOTE: using IObuf, the result encoding used will be the one used for
- * creating the output buffer, use the following macro to read it
- * from the stylesheet
- * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- * NOTE: using SAX, any encoding specified in the stylesheet will be lost
- * since the interface uses only UTF8
- *
- * Returns the number of by written to the main resource or -1 in case of
- * error.
- */
- int
- xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
- const char **params, const char *output,
- xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
- FILE * profile, xsltTransformContextPtr userCtxt)
- {
- xmlDocPtr tmp;
- int ret;
- if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
- return (-1);
- if ((SAX != NULL) && (IObuf != NULL))
- return (-1);
- /* unsupported yet */
- if (SAX != NULL) {
- XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
- return (-1);
- }
- tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
- userCtxt);
- if (tmp == NULL) {
- xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
- "xsltRunStylesheet : run failed\n");
- return (-1);
- }
- if (IObuf != NULL) {
- /* TODO: incomplete, IObuf output not progressive */
- ret = xsltSaveResultTo(IObuf, tmp, style);
- } else {
- ret = xsltSaveResultToFilename(output, tmp, style, 0);
- }
- xmlFreeDoc(tmp);
- return (ret);
- }
- /**
- * xsltRunStylesheet:
- * @style: a parsed XSLT stylesheet
- * @doc: a parsed XML document
- * @params: a NULL terminated array of parameters names/values tuples
- * @output: the URL/filename ot the generated resource if available
- * @SAX: a SAX handler for progressive callback output (not implemented yet)
- * @IObuf: an output buffer for progressive output (not implemented yet)
- *
- * Apply the stylesheet to the document and generate the output according
- * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
- *
- * NOTE: This may lead to a non-wellformed output XML wise !
- * NOTE: This may also result in multiple files being generated
- * NOTE: using IObuf, the result encoding used will be the one used for
- * creating the output buffer, use the following macro to read it
- * from the stylesheet
- * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- * NOTE: using SAX, any encoding specified in the stylesheet will be lost
- * since the interface uses only UTF8
- *
- * Returns the number of bytes written to the main resource or -1 in case of
- * error.
- */
- int
- xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
- const char **params, const char *output,
- xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
- {
- return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
- NULL, NULL));
- }
- static void
- xsltMessageWrapper(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
- xsltMessage(ctxt, node, inst);
- }
- /**
- * xsltRegisterAllElement:
- * @ctxt: the XPath context
- *
- * Registers all default XSLT elements in this context
- */
- void
- xsltRegisterAllElement(xsltTransformContextPtr ctxt)
- {
- xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
- XSLT_NAMESPACE,
- xsltApplyTemplates);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
- XSLT_NAMESPACE,
- xsltApplyImports);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
- XSLT_NAMESPACE,
- xsltCallTemplate);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
- XSLT_NAMESPACE,
- xsltElement);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
- XSLT_NAMESPACE,
- xsltAttribute);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
- XSLT_NAMESPACE,
- xsltText);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
- XSLT_NAMESPACE,
- xsltProcessingInstruction);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
- XSLT_NAMESPACE,
- xsltComment);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
- XSLT_NAMESPACE,
- xsltCopy);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
- XSLT_NAMESPACE,
- xsltValueOf);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
- XSLT_NAMESPACE,
- xsltNumber);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
- XSLT_NAMESPACE,
- xsltForEach);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
- XSLT_NAMESPACE,
- xsltIf);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
- XSLT_NAMESPACE,
- xsltChoose);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
- XSLT_NAMESPACE,
- xsltSort);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
- XSLT_NAMESPACE,
- xsltCopyOf);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
- XSLT_NAMESPACE,
- xsltMessageWrapper);
- /*
- * Those don't have callable entry points but are registered anyway
- */
- xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
- XSLT_NAMESPACE,
- xsltDebug);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
- XSLT_NAMESPACE,
- xsltDebug);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
- XSLT_NAMESPACE,
- xsltDebug);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
- XSLT_NAMESPACE,
- xsltDebug);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
- XSLT_NAMESPACE,
- xsltDebug);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
- XSLT_NAMESPACE,
- xsltDebug);
- xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
- XSLT_NAMESPACE,
- xsltDebug);
- }
|