123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047 |
- /*
- * xslt.c: Implemetation of an XSL Transformation 1.0 engine
- *
- * Reference:
- * XSLT specification
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * Associating Style Sheets with XML documents
- * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
- #define IN_LIBXSLT
- #include "libxslt.h"
- #include <string.h>
- #include <libxml/xmlmemory.h>
- #include <libxml/parser.h>
- #include <libxml/tree.h>
- #include <libxml/valid.h>
- #include <libxml/hash.h>
- #include <libxml/uri.h>
- #include <libxml/xmlerror.h>
- #include <libxml/parserInternals.h>
- #include <libxml/xpathInternals.h>
- #include <libxml/xpath.h>
- #include "xslt.h"
- #include "xsltInternals.h"
- #include "pattern.h"
- #include "variables.h"
- #include "namespaces.h"
- #include "attributes.h"
- #include "xsltutils.h"
- #include "imports.h"
- #include "keys.h"
- #include "documents.h"
- #include "extensions.h"
- #include "preproc.h"
- #include "extra.h"
- #include "security.h"
- #include "xsltlocale.h"
- #ifdef WITH_XSLT_DEBUG
- #define WITH_XSLT_DEBUG_PARSING
- /* #define WITH_XSLT_DEBUG_BLANKS */
- #endif
- const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
- const int xsltLibxsltVersion = LIBXSLT_VERSION;
- const int xsltLibxmlVersion = LIBXML_VERSION;
- #ifdef XSLT_REFACTORED
- const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
- #define XSLT_ELEMENT_CATEGORY_XSLT 0
- #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
- #define XSLT_ELEMENT_CATEGORY_LRE 2
- /*
- * xsltLiteralResultMarker:
- * Marker for Literal result elements, in order to avoid multiple attempts
- * to recognize such elements in the stylesheet's tree.
- * This marker is set on node->psvi during the initial traversal
- * of a stylesheet's node tree.
- *
- const xmlChar *xsltLiteralResultMarker =
- (const xmlChar *) "Literal Result Element";
- */
- /*
- * xsltXSLTTextMarker:
- * Marker for xsl:text elements. Used to recognize xsl:text elements
- * for post-processing of the stylesheet's tree, where those
- * elements are removed from the tree.
- */
- const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
- /*
- * xsltXSLTAttrMarker:
- * Marker for XSLT attribute on Literal Result Elements.
- */
- const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
- #endif
- #ifdef XSLT_LOCALE_WINAPI
- extern xmlRMutexPtr xsltLocaleMutex;
- #endif
- /*
- * Harmless but avoiding a problem when compiling against a
- * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
- */
- #ifndef LIBXML_DEBUG_ENABLED
- double xmlXPathStringEvalNumber(const xmlChar *str);
- #endif
- /*
- * Useful macros
- */
- #ifdef IS_BLANK
- #undef IS_BLANK
- #endif
- #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
- ((c) == 0x0D))
- #ifdef IS_BLANK_NODE
- #undef IS_BLANK_NODE
- #endif
- #define IS_BLANK_NODE(n) \
- (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
- /**
- * xsltParseContentError:
- *
- * @style: the stylesheet
- * @node: the node where the error occured
- *
- * Compile-time error function.
- */
- static void
- xsltParseContentError(xsltStylesheetPtr style,
- xmlNodePtr node)
- {
- if ((style == NULL) || (node == NULL))
- return;
- if (IS_XSLT_ELEM(node))
- xsltTransformError(NULL, style, node,
- "The XSLT-element '%s' is not allowed at this position.\n",
- node->name);
- else
- xsltTransformError(NULL, style, node,
- "The element '%s' is not allowed at this position.\n",
- node->name);
- style->errors++;
- }
- #ifdef XSLT_REFACTORED
- #else
- /**
- * exclPrefixPush:
- * @style: the transformation stylesheet
- * @value: the excluded namespace name to push on the stack
- *
- * Push an excluded namespace name on the stack
- *
- * Returns the new index in the stack or -1 if already present or
- * in case of error
- */
- static int
- exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
- {
- int i;
- if (style->exclPrefixMax == 0) {
- style->exclPrefixMax = 4;
- style->exclPrefixTab =
- (xmlChar * *)xmlMalloc(style->exclPrefixMax *
- sizeof(style->exclPrefixTab[0]));
- if (style->exclPrefixTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (-1);
- }
- }
- /* do not push duplicates */
- for (i = 0;i < style->exclPrefixNr;i++) {
- if (xmlStrEqual(style->exclPrefixTab[i], value))
- return(-1);
- }
- if (style->exclPrefixNr >= style->exclPrefixMax) {
- style->exclPrefixMax *= 2;
- style->exclPrefixTab =
- (xmlChar * *)xmlRealloc(style->exclPrefixTab,
- style->exclPrefixMax *
- sizeof(style->exclPrefixTab[0]));
- if (style->exclPrefixTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return (-1);
- }
- }
- style->exclPrefixTab[style->exclPrefixNr] = value;
- style->exclPrefix = value;
- return (style->exclPrefixNr++);
- }
- /**
- * exclPrefixPop:
- * @style: the transformation stylesheet
- *
- * Pop an excluded prefix value from the stack
- *
- * Returns the stored excluded prefix value
- */
- static xmlChar *
- exclPrefixPop(xsltStylesheetPtr style)
- {
- xmlChar *ret;
- if (style->exclPrefixNr <= 0)
- return (0);
- style->exclPrefixNr--;
- if (style->exclPrefixNr > 0)
- style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
- else
- style->exclPrefix = NULL;
- ret = style->exclPrefixTab[style->exclPrefixNr];
- style->exclPrefixTab[style->exclPrefixNr] = 0;
- return (ret);
- }
- #endif
- /************************************************************************
- * *
- * Helper functions *
- * *
- ************************************************************************/
- static int initialized = 0;
- /**
- * xsltInit:
- *
- * Initializes the processor (e.g. registers built-in extensions,
- * etc.)
- */
- void
- xsltInit (void) {
- if (initialized == 0) {
- initialized = 1;
- #ifdef XSLT_LOCALE_WINAPI
- xsltLocaleMutex = xmlNewRMutex();
- #endif
- xsltRegisterAllExtras();
- }
- }
- /**
- * xsltUninit:
- *
- * Uninitializes the processor.
- */
- void
- xsltUninit (void) {
- #ifdef XSLT_LOCALE_WINAPI
- xmlFreeRMutex(xsltLocaleMutex);
- xsltLocaleMutex = NULL;
- #endif
- initialized = 0;
- }
- /**
- * xsltIsBlank:
- * @str: a string
- *
- * Check if a string is ignorable
- *
- * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
- */
- int
- xsltIsBlank(xmlChar *str) {
- if (str == NULL)
- return(1);
- while (*str != 0) {
- if (!(IS_BLANK(*str))) return(0);
- str++;
- }
- return(1);
- }
- /************************************************************************
- * *
- * Routines to handle XSLT data structures *
- * *
- ************************************************************************/
- static xsltDecimalFormatPtr
- xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
- {
- xsltDecimalFormatPtr self;
- /* UTF-8 for 0x2030 */
- static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
- self = xmlMalloc(sizeof(xsltDecimalFormat));
- if (self != NULL) {
- self->next = NULL;
- self->nsUri = nsUri;
- self->name = name;
- /* Default values */
- self->digit = xmlStrdup(BAD_CAST("#"));
- self->patternSeparator = xmlStrdup(BAD_CAST(";"));
- self->decimalPoint = xmlStrdup(BAD_CAST("."));
- self->grouping = xmlStrdup(BAD_CAST(","));
- self->percent = xmlStrdup(BAD_CAST("%"));
- self->permille = xmlStrdup(BAD_CAST(permille));
- self->zeroDigit = xmlStrdup(BAD_CAST("0"));
- self->minusSign = xmlStrdup(BAD_CAST("-"));
- self->infinity = xmlStrdup(BAD_CAST("Infinity"));
- self->noNumber = xmlStrdup(BAD_CAST("NaN"));
- }
- return self;
- }
- static void
- xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
- {
- if (self != NULL) {
- if (self->digit)
- xmlFree(self->digit);
- if (self->patternSeparator)
- xmlFree(self->patternSeparator);
- if (self->decimalPoint)
- xmlFree(self->decimalPoint);
- if (self->grouping)
- xmlFree(self->grouping);
- if (self->percent)
- xmlFree(self->percent);
- if (self->permille)
- xmlFree(self->permille);
- if (self->zeroDigit)
- xmlFree(self->zeroDigit);
- if (self->minusSign)
- xmlFree(self->minusSign);
- if (self->infinity)
- xmlFree(self->infinity);
- if (self->noNumber)
- xmlFree(self->noNumber);
- if (self->name)
- xmlFree(self->name);
- xmlFree(self);
- }
- }
- static void
- xsltFreeDecimalFormatList(xsltStylesheetPtr self)
- {
- xsltDecimalFormatPtr iter;
- xsltDecimalFormatPtr tmp;
- if (self == NULL)
- return;
- iter = self->decimalFormat;
- while (iter != NULL) {
- tmp = iter->next;
- xsltFreeDecimalFormat(iter);
- iter = tmp;
- }
- }
- /**
- * xsltDecimalFormatGetByName:
- * @style: the XSLT stylesheet
- * @name: the decimal-format name to find
- *
- * Find decimal-format by name
- *
- * Returns the xsltDecimalFormatPtr
- */
- xsltDecimalFormatPtr
- xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
- {
- xsltDecimalFormatPtr result = NULL;
- if (name == NULL)
- return style->decimalFormat;
- while (style != NULL) {
- for (result = style->decimalFormat->next;
- result != NULL;
- result = result->next) {
- if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
- return result;
- }
- style = xsltNextImport(style);
- }
- return result;
- }
- /**
- * xsltDecimalFormatGetByQName:
- * @style: the XSLT stylesheet
- * @nsUri: the namespace URI of the QName
- * @name: the local part of the QName
- *
- * Find decimal-format by QName
- *
- * Returns the xsltDecimalFormatPtr
- */
- xsltDecimalFormatPtr
- xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
- const xmlChar *name)
- {
- xsltDecimalFormatPtr result = NULL;
- if (name == NULL)
- return style->decimalFormat;
- while (style != NULL) {
- for (result = style->decimalFormat->next;
- result != NULL;
- result = result->next) {
- if (xmlStrEqual(nsUri, result->nsUri) &&
- xmlStrEqual(name, result->name))
- return result;
- }
- style = xsltNextImport(style);
- }
- return result;
- }
- /**
- * xsltNewTemplate:
- *
- * Create a new XSLT Template
- *
- * Returns the newly allocated xsltTemplatePtr or NULL in case of error
- */
- static xsltTemplatePtr
- xsltNewTemplate(void) {
- xsltTemplatePtr cur;
- cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewTemplate : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltTemplate));
- cur->priority = XSLT_PAT_NO_PRIORITY;
- return(cur);
- }
- /**
- * xsltFreeTemplate:
- * @template: an XSLT template
- *
- * Free up the memory allocated by @template
- */
- static void
- xsltFreeTemplate(xsltTemplatePtr template) {
- if (template == NULL)
- return;
- if (template->match) xmlFree(template->match);
- /*
- * NOTE: @name and @nameURI are put into the string dict now.
- * if (template->name) xmlFree(template->name);
- * if (template->nameURI) xmlFree(template->nameURI);
- */
- /*
- if (template->mode) xmlFree(template->mode);
- if (template->modeURI) xmlFree(template->modeURI);
- */
- if (template->inheritedNs) xmlFree(template->inheritedNs);
- /* free profiling data */
- if (template->templCalledTab) xmlFree(template->templCalledTab);
- if (template->templCountTab) xmlFree(template->templCountTab);
- memset(template, -1, sizeof(xsltTemplate));
- xmlFree(template);
- }
- /**
- * xsltFreeTemplateList:
- * @template: an XSLT template list
- *
- * Free up the memory allocated by all the elements of @template
- */
- static void
- xsltFreeTemplateList(xsltTemplatePtr template) {
- xsltTemplatePtr cur;
- while (template != NULL) {
- cur = template;
- template = template->next;
- xsltFreeTemplate(cur);
- }
- }
- #ifdef XSLT_REFACTORED
- static void
- xsltFreeNsAliasList(xsltNsAliasPtr item)
- {
- xsltNsAliasPtr tmp;
- while (item) {
- tmp = item;
- item = item->next;
- xmlFree(tmp);
- }
- return;
- }
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- static void
- xsltFreeNamespaceMap(xsltNsMapPtr item)
- {
- xsltNsMapPtr tmp;
- while (item) {
- tmp = item;
- item = item->next;
- xmlFree(tmp);
- }
- return;
- }
- static xsltNsMapPtr
- xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
- xmlDocPtr doc,
- xmlNsPtr ns,
- xmlNodePtr elem)
- {
- xsltNsMapPtr ret;
- if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
- return(NULL);
- ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
- if (ret == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error: (xsltNewNamespaceMapItem) "
- "memory allocation failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltNsMap));
- ret->doc = doc;
- ret->ns = ns;
- ret->origNsName = ns->href;
- /*
- * Store the item at current stylesheet-level.
- */
- if (cctxt->psData->nsMap != NULL)
- ret->next = cctxt->psData->nsMap;
- cctxt->psData->nsMap = ret;
- return(ret);
- }
- #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
- /**
- * xsltCompilerVarInfoFree:
- * @cctxt: the compilation context
- *
- * Frees the list of information for vars/params.
- */
- static void
- xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
- {
- xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
- while (ivar) {
- ivartmp = ivar;
- ivar = ivar->next;
- xmlFree(ivartmp);
- }
- }
- /**
- * xsltCompilerCtxtFree:
- *
- * Free an XSLT compiler context.
- */
- static void
- xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
- {
- if (cctxt == NULL)
- return;
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Freeing compilation context\n");
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max inodes: %d\n", cctxt->maxNodeInfos);
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max LREs : %d\n", cctxt->maxLREs);
- #endif
- /*
- * Free node-infos.
- */
- if (cctxt->inodeList != NULL) {
- xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
- while (cur != NULL) {
- tmp = cur;
- cur = cur->next;
- xmlFree(tmp);
- }
- }
- if (cctxt->tmpList != NULL)
- xsltPointerListFree(cctxt->tmpList);
- if (cctxt->nsAliases != NULL)
- xsltFreeNsAliasList(cctxt->nsAliases);
- if (cctxt->ivars)
- xsltCompilerVarInfoFree(cctxt);
- xmlFree(cctxt);
- }
- /**
- * xsltCompilerCreate:
- *
- * Creates an XSLT compiler context.
- *
- * Returns the pointer to the created xsltCompilerCtxt or
- * NULL in case of an internal error.
- */
- static xsltCompilerCtxtPtr
- xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
- xsltCompilerCtxtPtr ret;
- ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
- if (ret == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltCompilerCreate: allocation of compiler "
- "context failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltCompilerCtxt));
- ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
- ret->tmpList = xsltPointerListCreate(20);
- if (ret->tmpList == NULL) {
- goto internal_err;
- }
- return(ret);
- internal_err:
- xsltCompilationCtxtFree(ret);
- return(NULL);
- }
- static void
- xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
- {
- xsltEffectiveNsPtr tmp;
- while (first != NULL) {
- tmp = first;
- first = first->nextInStore;
- xmlFree(tmp);
- }
- }
- static void
- xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
- {
- if (data == NULL)
- return;
- if (data->inScopeNamespaces != NULL) {
- int i;
- xsltNsListContainerPtr nsi;
- xsltPointerListPtr list =
- (xsltPointerListPtr) data->inScopeNamespaces;
- for (i = 0; i < list->number; i++) {
- /*
- * REVISIT TODO: Free info of in-scope namespaces.
- */
- nsi = (xsltNsListContainerPtr) list->items[i];
- if (nsi->list != NULL)
- xmlFree(nsi->list);
- xmlFree(nsi);
- }
- xsltPointerListFree(list);
- data->inScopeNamespaces = NULL;
- }
- if (data->exclResultNamespaces != NULL) {
- int i;
- xsltPointerListPtr list = (xsltPointerListPtr)
- data->exclResultNamespaces;
- for (i = 0; i < list->number; i++)
- xsltPointerListFree((xsltPointerListPtr) list->items[i]);
- xsltPointerListFree(list);
- data->exclResultNamespaces = NULL;
- }
- if (data->extElemNamespaces != NULL) {
- xsltPointerListPtr list = (xsltPointerListPtr)
- data->extElemNamespaces;
- int i;
- for (i = 0; i < list->number; i++)
- xsltPointerListFree((xsltPointerListPtr) list->items[i]);
- xsltPointerListFree(list);
- data->extElemNamespaces = NULL;
- }
- if (data->effectiveNs) {
- xsltLREEffectiveNsNodesFree(data->effectiveNs);
- data->effectiveNs = NULL;
- }
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- xsltFreeNamespaceMap(data->nsMap);
- #endif
- xmlFree(data);
- }
- static xsltPrincipalStylesheetDataPtr
- xsltNewPrincipalStylesheetData(void)
- {
- xsltPrincipalStylesheetDataPtr ret;
- ret = (xsltPrincipalStylesheetDataPtr)
- xmlMalloc(sizeof(xsltPrincipalStylesheetData));
- if (ret == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
- /*
- * Global list of in-scope namespaces.
- */
- ret->inScopeNamespaces = xsltPointerListCreate(-1);
- if (ret->inScopeNamespaces == NULL)
- goto internal_err;
- /*
- * Global list of excluded result ns-decls.
- */
- ret->exclResultNamespaces = xsltPointerListCreate(-1);
- if (ret->exclResultNamespaces == NULL)
- goto internal_err;
- /*
- * Global list of extension instruction namespace names.
- */
- ret->extElemNamespaces = xsltPointerListCreate(-1);
- if (ret->extElemNamespaces == NULL)
- goto internal_err;
- return(ret);
- internal_err:
- return(NULL);
- }
- #endif
- /**
- * xsltNewStylesheetInternal:
- * @parent: the parent stylesheet or NULL
- *
- * Create a new XSLT Stylesheet
- *
- * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
- */
- static xsltStylesheetPtr
- xsltNewStylesheetInternal(xsltStylesheetPtr parent) {
- xsltStylesheetPtr ret = NULL;
- ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
- if (ret == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewStylesheet : malloc failed\n");
- goto internal_err;
- }
- memset(ret, 0, sizeof(xsltStylesheet));
- ret->parent = parent;
- ret->omitXmlDeclaration = -1;
- ret->standalone = -1;
- ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
- ret->indent = -1;
- ret->errors = 0;
- ret->warnings = 0;
- ret->exclPrefixNr = 0;
- ret->exclPrefixMax = 0;
- ret->exclPrefixTab = NULL;
- ret->extInfos = NULL;
- ret->extrasNr = 0;
- ret->internalized = 1;
- ret->literal_result = 0;
- ret->forwards_compatible = 0;
- ret->dict = xmlDictCreate();
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "creating dictionary for stylesheet\n");
- #endif
- if (parent == NULL) {
- ret->principal = ret;
- ret->xpathCtxt = xmlXPathNewContext(NULL);
- if (ret->xpathCtxt == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewStylesheet: xmlXPathNewContext failed\n");
- goto internal_err;
- }
- if (xmlXPathContextSetCache(ret->xpathCtxt, 1, -1, 0) == -1)
- goto internal_err;
- } else {
- ret->principal = parent->principal;
- }
- xsltInit();
- return(ret);
- internal_err:
- if (ret != NULL)
- xsltFreeStylesheet(ret);
- return(NULL);
- }
- /**
- * xsltNewStylesheet:
- *
- * Create a new XSLT Stylesheet
- *
- * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
- */
- xsltStylesheetPtr
- xsltNewStylesheet(void) {
- return xsltNewStylesheetInternal(NULL);
- }
- /**
- * xsltAllocateExtra:
- * @style: an XSLT stylesheet
- *
- * Allocate an extra runtime information slot statically while compiling
- * the stylesheet and return its number
- *
- * Returns the number of the slot
- */
- int
- xsltAllocateExtra(xsltStylesheetPtr style)
- {
- return(style->extrasNr++);
- }
- /**
- * xsltAllocateExtraCtxt:
- * @ctxt: an XSLT transformation context
- *
- * Allocate an extra runtime information slot at run-time
- * and return its number
- * This make sure there is a slot ready in the transformation context
- *
- * Returns the number of the slot
- */
- int
- xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
- {
- if (ctxt->extrasNr >= ctxt->extrasMax) {
- int i;
- if (ctxt->extrasNr == 0) {
- ctxt->extrasMax = 20;
- ctxt->extras = (xsltRuntimeExtraPtr)
- xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
- if (ctxt->extras == NULL) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltAllocateExtraCtxt: out of memory\n");
- return(0);
- }
- for (i = 0;i < ctxt->extrasMax;i++) {
- ctxt->extras[i].info = NULL;
- ctxt->extras[i].deallocate = NULL;
- ctxt->extras[i].val.ptr = NULL;
- }
- } else {
- xsltRuntimeExtraPtr tmp;
- ctxt->extrasMax += 100;
- tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
- ctxt->extrasMax * sizeof(xsltRuntimeExtra));
- if (tmp == NULL) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltAllocateExtraCtxt: out of memory\n");
- return(0);
- }
- ctxt->extras = tmp;
- for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
- ctxt->extras[i].info = NULL;
- ctxt->extras[i].deallocate = NULL;
- ctxt->extras[i].val.ptr = NULL;
- }
- }
- }
- return(ctxt->extrasNr++);
- }
- /**
- * xsltFreeStylesheetList:
- * @style: an XSLT stylesheet list
- *
- * Free up the memory allocated by the list @style
- */
- static void
- xsltFreeStylesheetList(xsltStylesheetPtr style) {
- xsltStylesheetPtr next;
- while (style != NULL) {
- next = style->next;
- xsltFreeStylesheet(style);
- style = next;
- }
- }
- /**
- * xsltCleanupStylesheetTree:
- *
- * @doc: the document-node
- * @node: the element where the stylesheet is rooted at
- *
- * Actually @node need not be the document-element, but
- * currently Libxslt does not support embedded stylesheets.
- *
- * Returns 0 if OK, -1 on API or internal errors.
- */
- static int
- xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
- xmlNodePtr rootElem ATTRIBUTE_UNUSED)
- {
- #if 0 /* TODO: Currently disabled, since probably not needed. */
- xmlNodePtr cur;
- if ((doc == NULL) || (rootElem == NULL) ||
- (rootElem->type != XML_ELEMENT_NODE) ||
- (doc != rootElem->doc))
- return(-1);
- /*
- * Cleanup was suggested by Aleksey Sanin:
- * Clear the PSVI field to avoid problems if the
- * node-tree of the stylesheet is intended to be used for
- * further processing by the user (e.g. for compiling it
- * once again - although not recommended).
- */
- cur = rootElem;
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE) {
- /*
- * Clear the PSVI field.
- */
- cur->psvi = NULL;
- if (cur->children) {
- cur = cur->children;
- continue;
- }
- }
- leave_node:
- if (cur == rootElem)
- break;
- if (cur->next != NULL)
- cur = cur->next;
- else {
- cur = cur->parent;
- if (cur == NULL)
- break;
- goto leave_node;
- }
- }
- #endif /* #if 0 */
- return(0);
- }
- /**
- * xsltFreeStylesheet:
- * @style: an XSLT stylesheet
- *
- * Free up the memory allocated by @style
- */
- void
- xsltFreeStylesheet(xsltStylesheetPtr style)
- {
- if (style == NULL)
- return;
- #ifdef XSLT_REFACTORED
- /*
- * Start with a cleanup of the main stylesheet's doc.
- */
- if ((style->principal == style) && (style->doc))
- xsltCleanupStylesheetTree(style->doc,
- xmlDocGetRootElement(style->doc));
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /*
- * Restore changed ns-decls before freeing the document.
- */
- if ((style->doc != NULL) &&
- XSLT_HAS_INTERNAL_NSMAP(style))
- {
- xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
- style->doc);
- }
- #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
- #else
- /*
- * Start with a cleanup of the main stylesheet's doc.
- */
- if ((style->parent == NULL) && (style->doc))
- xsltCleanupStylesheetTree(style->doc,
- xmlDocGetRootElement(style->doc));
- #endif /* XSLT_REFACTORED */
- xsltFreeKeys(style);
- xsltFreeExts(style);
- xsltFreeTemplateHashes(style);
- xsltFreeDecimalFormatList(style);
- xsltFreeTemplateList(style->templates);
- xsltFreeAttributeSetsHashes(style);
- xsltFreeNamespaceAliasHashes(style);
- xsltFreeStylePreComps(style);
- /*
- * Free documents of all included stylsheet modules of this
- * stylesheet level.
- */
- xsltFreeStyleDocuments(style);
- /*
- * TODO: Best time to shutdown extension stuff?
- */
- xsltShutdownExts(style);
- if (style->variables != NULL)
- xsltFreeStackElemList(style->variables);
- if (style->cdataSection != NULL)
- xmlHashFree(style->cdataSection, NULL);
- if (style->stripSpaces != NULL)
- xmlHashFree(style->stripSpaces, NULL);
- if (style->nsHash != NULL)
- xmlHashFree(style->nsHash, NULL);
- if (style->exclPrefixTab != NULL)
- xmlFree(style->exclPrefixTab);
- if (style->method != NULL)
- xmlFree(style->method);
- if (style->methodURI != NULL)
- xmlFree(style->methodURI);
- if (style->version != NULL)
- xmlFree(style->version);
- if (style->encoding != NULL)
- xmlFree(style->encoding);
- if (style->doctypePublic != NULL)
- xmlFree(style->doctypePublic);
- if (style->doctypeSystem != NULL)
- xmlFree(style->doctypeSystem);
- if (style->mediaType != NULL)
- xmlFree(style->mediaType);
- if (style->attVTs)
- xsltFreeAVTList(style->attVTs);
- if (style->imports != NULL)
- xsltFreeStylesheetList(style->imports);
- #ifdef XSLT_REFACTORED
- /*
- * If this is the principal stylesheet, then
- * free its internal data.
- */
- if (style->principal == style) {
- if (style->principalData) {
- xsltFreePrincipalStylesheetData(style->principalData);
- style->principalData = NULL;
- }
- }
- #endif
- /*
- * Better to free the main document of this stylesheet level
- * at the end - so here.
- */
- if (style->doc != NULL) {
- xmlFreeDoc(style->doc);
- }
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "freeing dictionary from stylesheet\n");
- #endif
- xmlDictFree(style->dict);
- if (style->xpathCtxt != NULL)
- xmlXPathFreeContext(style->xpathCtxt);
- memset(style, -1, sizeof(xsltStylesheet));
- xmlFree(style);
- }
- /************************************************************************
- * *
- * Parsing of an XSLT Stylesheet *
- * *
- ************************************************************************/
- #ifdef XSLT_REFACTORED
- /*
- * This is now performed in an optimized way in xsltParseXSLTTemplate.
- */
- #else
- /**
- * xsltGetInheritedNsList:
- * @style: the stylesheet
- * @template: the template
- * @node: the current node
- *
- * Search all the namespace applying to a given element except the ones
- * from excluded output prefixes currently in scope. Initialize the
- * template inheritedNs list with it.
- *
- * Returns the number of entries found
- */
- static int
- xsltGetInheritedNsList(xsltStylesheetPtr style,
- xsltTemplatePtr template,
- xmlNodePtr node)
- {
- xmlNsPtr cur;
- xmlNsPtr *ret = NULL;
- int nbns = 0;
- int maxns = 10;
- int i;
- if ((style == NULL) || (template == NULL) || (node == NULL) ||
- (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
- return(0);
- while (node != NULL) {
- if (node->type == XML_ELEMENT_NODE) {
- cur = node->nsDef;
- while (cur != NULL) {
- if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
- goto skip_ns;
- if ((cur->prefix != NULL) &&
- (xsltCheckExtPrefix(style, cur->prefix)))
- goto skip_ns;
- /*
- * Check if this namespace was excluded.
- * Note that at this point only the exclusions defined
- * on the topmost stylesheet element are in the exclusion-list.
- */
- for (i = 0;i < style->exclPrefixNr;i++) {
- if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
- goto skip_ns;
- }
- if (ret == NULL) {
- ret =
- (xmlNsPtr *) xmlMalloc((maxns + 1) *
- sizeof(xmlNsPtr));
- if (ret == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltGetInheritedNsList : out of memory!\n");
- return(0);
- }
- ret[nbns] = NULL;
- }
- /*
- * Skip shadowed namespace bindings.
- */
- for (i = 0; i < nbns; i++) {
- if ((cur->prefix == ret[i]->prefix) ||
- (xmlStrEqual(cur->prefix, ret[i]->prefix)))
- break;
- }
- if (i >= nbns) {
- if (nbns >= maxns) {
- maxns *= 2;
- ret = (xmlNsPtr *) xmlRealloc(ret,
- (maxns +
- 1) *
- sizeof(xmlNsPtr));
- if (ret == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltGetInheritedNsList : realloc failed!\n");
- return(0);
- }
- }
- ret[nbns++] = cur;
- ret[nbns] = NULL;
- }
- skip_ns:
- cur = cur->next;
- }
- }
- node = node->parent;
- }
- if (nbns != 0) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "template has %d inherited namespaces\n", nbns);
- #endif
- template->inheritedNsNr = nbns;
- template->inheritedNs = ret;
- }
- return (nbns);
- }
- #endif /* else of XSLT_REFACTORED */
- /**
- * xsltParseStylesheetOutput:
- * @style: the XSLT stylesheet
- * @cur: the "output" element
- *
- * parse an XSLT stylesheet output element and record
- * information related to the stylesheet output
- */
- void
- xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
- {
- xmlChar *elements,
- *prop;
- xmlChar *element,
- *end;
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
- if (prop != NULL) {
- if (style->version != NULL)
- xmlFree(style->version);
- style->version = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
- if (prop != NULL) {
- if (style->encoding != NULL)
- xmlFree(style->encoding);
- style->encoding = prop;
- }
- /* relaxed to support xt:document
- * TODO KB: What does "relaxed to support xt:document" mean?
- */
- prop = xmlGetNsProp(cur, (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;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &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(NULL, style, cur,
- "invalid value for method: %s\n", prop);
- if (style != NULL) style->warnings++;
- xmlFree(prop);
- }
- } else {
- style->method = prop;
- style->methodURI = xmlStrdup(URI);
- }
- }
- prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
- if (prop != NULL) {
- if (style->doctypeSystem != NULL)
- xmlFree(style->doctypeSystem);
- style->doctypeSystem = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
- if (prop != NULL) {
- if (style->doctypePublic != NULL)
- xmlFree(style->doctypePublic);
- style->doctypePublic = prop;
- }
- prop = xmlGetNsProp(cur, (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(NULL, style, cur,
- "invalid value for standalone: %s\n", prop);
- style->errors++;
- }
- xmlFree(prop);
- }
- prop = xmlGetNsProp(cur, (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(NULL, style, cur,
- "invalid value for indent: %s\n", prop);
- style->errors++;
- }
- xmlFree(prop);
- }
- prop = xmlGetNsProp(cur, (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(NULL, style, cur,
- "invalid value for omit-xml-declaration: %s\n",
- prop);
- style->errors++;
- }
- xmlFree(prop);
- }
- elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
- NULL);
- if (elements != NULL) {
- if (style->cdataSection == NULL)
- style->cdataSection = xmlHashCreate(10);
- if (style->cdataSection == NULL)
- return;
- element = elements;
- while (*element != 0) {
- while (IS_BLANK(*element))
- element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK(*end)))
- end++;
- element = xmlStrndup(element, end - element);
- if (element) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add cdata section output element %s\n",
- element);
- #endif
- if (xmlValidateQName(BAD_CAST element, 0) != 0) {
- xsltTransformError(NULL, style, cur,
- "Attribute 'cdata-section-elements': The value "
- "'%s' is not a valid QName.\n", element);
- xmlFree(element);
- style->errors++;
- } else {
- const xmlChar *URI;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &element);
- if (element == NULL) {
- /*
- * TODO: We'll report additionally an error
- * via the stylesheet's error handling.
- */
- xsltTransformError(NULL, style, cur,
- "Attribute 'cdata-section-elements': "
- "Not a valid QName.\n");
- style->errors++;
- } else {
- xmlNsPtr ns;
- /*
- * XSLT-1.0 "Each QName is expanded into an
- * expanded-name using the namespace declarations in
- * effect on the xsl:output element in which the QName
- * occurs; if there is a default namespace, it is used
- * for QNames that do not have a prefix"
- * NOTE: Fix of bug #339570.
- */
- if (URI == NULL) {
- ns = xmlSearchNs(style->doc, cur, NULL);
- if (ns != NULL)
- URI = ns->href;
- }
- xmlHashAddEntry2(style->cdataSection, element, URI,
- (void *) "cdata");
- xmlFree(element);
- }
- }
- }
- element = end;
- }
- xmlFree(elements);
- }
- prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
- if (prop != NULL) {
- if (style->mediaType)
- xmlFree(style->mediaType);
- style->mediaType = prop;
- }
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
- }
- /**
- * xsltParseStylesheetDecimalFormat:
- * @style: the XSLT stylesheet
- * @cur: the "decimal-format" element
- *
- * <!-- Category: top-level-element -->
- * <xsl:decimal-format
- * name = qname, decimal-separator = char, grouping-separator = char,
- * infinity = string, minus-sign = char, NaN = string, percent = char
- * per-mille = char, zero-digit = char, digit = char,
- * pattern-separator = char />
- *
- * parse an XSLT stylesheet decimal-format element and
- * and record the formatting characteristics
- */
- static void
- xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
- {
- xmlChar *prop;
- xsltDecimalFormatPtr format;
- xsltDecimalFormatPtr iter;
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- format = style->decimalFormat;
- prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
- if (prop != NULL) {
- const xmlChar *nsUri;
- if (xmlValidateQName(prop, 0) != 0) {
- xsltTransformError(NULL, style, cur,
- "xsl:decimal-format: Invalid QName '%s'.\n", prop);
- style->warnings++;
- xmlFree(prop);
- return;
- }
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- nsUri = xsltGetQNameURI(cur, &prop);
- if (prop == NULL) {
- style->warnings++;
- return;
- }
- format = xsltDecimalFormatGetByQName(style, nsUri, prop);
- if (format != NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
- style->warnings++;
- xmlFree(prop);
- return;
- }
- format = xsltNewDecimalFormat(nsUri, prop);
- if (format == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
- style->errors++;
- xmlFree(prop);
- return;
- }
- /* Append new decimal-format structure */
- for (iter = style->decimalFormat; iter->next; iter = iter->next)
- ;
- if (iter)
- iter->next = format;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
- if (prop != NULL) {
- if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
- format->decimalPoint = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
- if (prop != NULL) {
- if (format->grouping != NULL) xmlFree(format->grouping);
- format->grouping = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
- if (prop != NULL) {
- if (format->infinity != NULL) xmlFree(format->infinity);
- format->infinity = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
- if (prop != NULL) {
- if (format->minusSign != NULL) xmlFree(format->minusSign);
- format->minusSign = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
- if (prop != NULL) {
- if (format->noNumber != NULL) xmlFree(format->noNumber);
- format->noNumber = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
- if (prop != NULL) {
- if (format->percent != NULL) xmlFree(format->percent);
- format->percent = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
- if (prop != NULL) {
- if (format->permille != NULL) xmlFree(format->permille);
- format->permille = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
- if (prop != NULL) {
- if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
- format->zeroDigit = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
- if (prop != NULL) {
- if (format->digit != NULL) xmlFree(format->digit);
- format->digit = prop;
- }
- prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
- if (prop != NULL) {
- if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
- format->patternSeparator = prop;
- }
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
- }
- /**
- * xsltParseStylesheetPreserveSpace:
- * @style: the XSLT stylesheet
- * @cur: the "preserve-space" element
- *
- * parse an XSLT stylesheet preserve-space element and record
- * elements needing preserving
- */
- static void
- xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
- xmlChar *elements;
- xmlChar *element, *end;
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
- if (elements == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
- if (style != NULL) style->warnings++;
- return;
- }
- if (style->stripSpaces == NULL)
- style->stripSpaces = xmlHashCreate(10);
- if (style->stripSpaces == NULL)
- return;
- element = elements;
- while (*element != 0) {
- while (IS_BLANK(*element)) element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- element = xmlStrndup(element, end - element);
- if (element) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add preserved space element %s\n", element);
- #endif
- if (xmlStrEqual(element, (const xmlChar *)"*")) {
- style->stripAll = -1;
- } else {
- const xmlChar *URI;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &element);
- xmlHashAddEntry2(style->stripSpaces, element, URI,
- (xmlChar *) "preserve");
- }
- xmlFree(element);
- }
- element = end;
- }
- xmlFree(elements);
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
- }
- #ifdef XSLT_REFACTORED
- #else
- /**
- * xsltParseStylesheetExtPrefix:
- * @style: the XSLT stylesheet
- * @template: the "extension-element-prefixes" prefix
- *
- * parse an XSLT stylesheet's "extension-element-prefix" attribute value
- * and register the namespaces of extension instruction.
- * SPEC "A namespace is designated as an extension namespace by using
- * an extension-element-prefixes attribute on:
- * 1) an xsl:stylesheet element
- * 2) an xsl:extension-element-prefixes attribute on a
- * literal result element
- * 3) an extension instruction."
- */
- static void
- xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
- int isXsltElem) {
- xmlChar *prefixes;
- xmlChar *prefix, *end;
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- if (isXsltElem) {
- /* For xsl:stylesheet/xsl:transform. */
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"extension-element-prefixes", NULL);
- } else {
- /* For literal result elements and extension instructions. */
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
- }
- if (prefixes == NULL) {
- return;
- }
- prefix = prefixes;
- while (*prefix != 0) {
- while (IS_BLANK(*prefix)) prefix++;
- if (*prefix == 0)
- break;
- end = prefix;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- prefix = xmlStrndup(prefix, end - prefix);
- if (prefix) {
- xmlNsPtr ns;
- if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
- ns = xmlSearchNs(style->doc, cur, NULL);
- else
- ns = xmlSearchNs(style->doc, cur, prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:extension-element-prefix : undefined namespace %s\n",
- prefix);
- if (style != NULL) style->warnings++;
- } else {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add extension prefix %s\n", prefix);
- #endif
- xsltRegisterExtPrefix(style, prefix, ns->href);
- }
- xmlFree(prefix);
- }
- prefix = end;
- }
- xmlFree(prefixes);
- }
- #endif /* else of XSLT_REFACTORED */
- /**
- * xsltParseStylesheetStripSpace:
- * @style: the XSLT stylesheet
- * @cur: the "strip-space" element
- *
- * parse an XSLT stylesheet's strip-space element and record
- * the elements needing stripping
- */
- static void
- xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
- xmlChar *elements;
- xmlChar *element, *end;
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
- if (elements == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetStripSpace: missing elements attribute\n");
- if (style != NULL) style->warnings++;
- return;
- }
- if (style->stripSpaces == NULL)
- style->stripSpaces = xmlHashCreate(10);
- if (style->stripSpaces == NULL)
- return;
- element = elements;
- while (*element != 0) {
- while (IS_BLANK(*element)) element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- element = xmlStrndup(element, end - element);
- if (element) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add stripped space element %s\n", element);
- #endif
- if (xmlStrEqual(element, (const xmlChar *)"*")) {
- style->stripAll = 1;
- } else {
- const xmlChar *URI;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &element);
- xmlHashAddEntry2(style->stripSpaces, element, URI,
- (xmlChar *) "strip");
- }
- xmlFree(element);
- }
- element = end;
- }
- xmlFree(elements);
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
- }
- #ifdef XSLT_REFACTORED
- #else
- /**
- * xsltParseStylesheetExcludePrefix:
- * @style: the XSLT stylesheet
- * @cur: the current point in the stylesheet
- *
- * parse an XSLT stylesheet exclude prefix and record
- * namespaces needing stripping
- *
- * Returns the number of Excluded prefixes added at that level
- */
- static int
- xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
- int isXsltElem)
- {
- int nb = 0;
- xmlChar *prefixes;
- xmlChar *prefix, *end;
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return(0);
- if (isXsltElem)
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"exclude-result-prefixes", NULL);
- else
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
- if (prefixes == NULL) {
- return(0);
- }
- prefix = prefixes;
- while (*prefix != 0) {
- while (IS_BLANK(*prefix)) prefix++;
- if (*prefix == 0)
- break;
- end = prefix;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- prefix = xmlStrndup(prefix, end - prefix);
- if (prefix) {
- xmlNsPtr ns;
- if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
- ns = xmlSearchNs(style->doc, cur, NULL);
- else
- ns = xmlSearchNs(style->doc, cur, prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:exclude-result-prefixes : undefined namespace %s\n",
- prefix);
- if (style != NULL) style->warnings++;
- } else {
- if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "exclude result prefix %s\n", prefix);
- #endif
- nb++;
- }
- }
- xmlFree(prefix);
- }
- prefix = end;
- }
- xmlFree(prefixes);
- return(nb);
- }
- #endif /* else of XSLT_REFACTORED */
- #ifdef XSLT_REFACTORED
- /*
- * xsltTreeEnsureXMLDecl:
- * @doc: the doc
- *
- * BIG NOTE:
- * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
- * Ensures that there is an XML namespace declaration on the doc.
- *
- * Returns the XML ns-struct or NULL on API and internal errors.
- */
- static xmlNsPtr
- xsltTreeEnsureXMLDecl(xmlDocPtr doc)
- {
- if (doc == NULL)
- return (NULL);
- if (doc->oldNs != NULL)
- return (doc->oldNs);
- {
- xmlNsPtr ns;
- ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
- if (ns == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltTreeEnsureXMLDecl: Failed to allocate "
- "the XML namespace.\n");
- return (NULL);
- }
- memset(ns, 0, sizeof(xmlNs));
- ns->type = XML_LOCAL_NAMESPACE;
- /*
- * URGENT TODO: revisit this.
- */
- #ifdef LIBXML_NAMESPACE_DICT
- if (doc->dict)
- ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
- else
- ns->href = xmlStrdup(XML_XML_NAMESPACE);
- #else
- ns->href = xmlStrdup(XML_XML_NAMESPACE);
- #endif
- ns->prefix = xmlStrdup((const xmlChar *)"xml");
- doc->oldNs = ns;
- return (ns);
- }
- }
- /*
- * xsltTreeAcquireStoredNs:
- * @doc: the doc
- * @nsName: the namespace name
- * @prefix: the prefix
- *
- * BIG NOTE:
- * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
- * Creates or reuses an xmlNs struct on doc->oldNs with
- * the given prefix and namespace name.
- *
- * Returns the aquired ns struct or NULL in case of an API
- * or internal error.
- */
- static xmlNsPtr
- xsltTreeAcquireStoredNs(xmlDocPtr doc,
- const xmlChar *nsName,
- const xmlChar *prefix)
- {
- xmlNsPtr ns;
- if (doc == NULL)
- return (NULL);
- if (doc->oldNs != NULL)
- ns = doc->oldNs;
- else
- ns = xsltTreeEnsureXMLDecl(doc);
- if (ns == NULL)
- return (NULL);
- if (ns->next != NULL) {
- /* Reuse. */
- ns = ns->next;
- while (ns != NULL) {
- if ((ns->prefix == NULL) != (prefix == NULL)) {
- /* NOP */
- } else if (prefix == NULL) {
- if (xmlStrEqual(ns->href, nsName))
- return (ns);
- } else {
- if ((ns->prefix[0] == prefix[0]) &&
- xmlStrEqual(ns->prefix, prefix) &&
- xmlStrEqual(ns->href, nsName))
- return (ns);
- }
- if (ns->next == NULL)
- break;
- ns = ns->next;
- }
- }
- /* Create. */
- ns->next = xmlNewNs(NULL, nsName, prefix);
- return (ns->next);
- }
- /**
- * xsltLREBuildEffectiveNs:
- *
- * Apply ns-aliasing on the namespace of the given @elem and
- * its attributes.
- */
- static int
- xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr elem)
- {
- xmlNsPtr ns;
- xsltNsAliasPtr alias;
- if ((cctxt == NULL) || (elem == NULL))
- return(-1);
- if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
- return(0);
- alias = cctxt->nsAliases;
- while (alias != NULL) {
- if ( /* If both namespaces are NULL... */
- ( (elem->ns == NULL) &&
- ((alias->literalNs == NULL) ||
- (alias->literalNs->href == NULL)) ) ||
- /* ... or both namespace are equal */
- ( (elem->ns != NULL) &&
- (alias->literalNs != NULL) &&
- xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
- {
- if ((alias->targetNs != NULL) &&
- (alias->targetNs->href != NULL))
- {
- /*
- * Convert namespace.
- */
- if (elem->doc == alias->docOfTargetNs) {
- /*
- * This is the nice case: same docs.
- * This will eventually assign a ns-decl which
- * is shadowed, but this has no negative effect on
- * the generation of the result tree.
- */
- elem->ns = alias->targetNs;
- } else {
- /*
- * This target xmlNs originates from a different
- * stylesheet tree. Try to locate it in the
- * in-scope namespaces.
- * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
- */
- ns = xmlSearchNs(elem->doc, elem,
- alias->targetNs->prefix);
- /*
- * If no matching ns-decl found, then assign a
- * ns-decl stored in xmlDoc.
- */
- if ((ns == NULL) ||
- (! xmlStrEqual(ns->href, alias->targetNs->href)))
- {
- /*
- * BIG NOTE: The use of xsltTreeAcquireStoredNs()
- * is not very efficient, but currently I don't
- * see an other way of *safely* changing a node's
- * namespace, since the xmlNs struct in
- * alias->targetNs might come from an other
- * stylesheet tree. So we need to anchor it in the
- * current document, without adding it to the tree,
- * which would otherwise change the in-scope-ns
- * semantic of the tree.
- */
- ns = xsltTreeAcquireStoredNs(elem->doc,
- alias->targetNs->href,
- alias->targetNs->prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error in "
- "xsltLREBuildEffectiveNs(): "
- "failed to acquire a stored "
- "ns-declaration.\n");
- cctxt->style->errors++;
- return(-1);
- }
- }
- elem->ns = ns;
- }
- } else {
- /*
- * Move into or leave in the NULL namespace.
- */
- elem->ns = NULL;
- }
- break;
- }
- alias = alias->next;
- }
- /*
- * Same with attributes of literal result elements.
- */
- if (elem->properties != NULL) {
- xmlAttrPtr attr = elem->properties;
- while (attr != NULL) {
- if (attr->ns == NULL) {
- attr = attr->next;
- continue;
- }
- alias = cctxt->nsAliases;
- while (alias != NULL) {
- if ( /* If both namespaces are NULL... */
- ( (elem->ns == NULL) &&
- ((alias->literalNs == NULL) ||
- (alias->literalNs->href == NULL)) ) ||
- /* ... or both namespace are equal */
- ( (elem->ns != NULL) &&
- (alias->literalNs != NULL) &&
- xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
- {
- if ((alias->targetNs != NULL) &&
- (alias->targetNs->href != NULL))
- {
- if (elem->doc == alias->docOfTargetNs) {
- elem->ns = alias->targetNs;
- } else {
- ns = xmlSearchNs(elem->doc, elem,
- alias->targetNs->prefix);
- if ((ns == NULL) ||
- (! xmlStrEqual(ns->href, alias->targetNs->href)))
- {
- ns = xsltTreeAcquireStoredNs(elem->doc,
- alias->targetNs->href,
- alias->targetNs->prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error in "
- "xsltLREBuildEffectiveNs(): "
- "failed to acquire a stored "
- "ns-declaration.\n");
- cctxt->style->errors++;
- return(-1);
- }
- }
- elem->ns = ns;
- }
- } else {
- /*
- * Move into or leave in the NULL namespace.
- */
- elem->ns = NULL;
- }
- break;
- }
- alias = alias->next;
- }
- attr = attr->next;
- }
- }
- return(0);
- }
- /**
- * xsltLREBuildEffectiveNsNodes:
- *
- * Computes the effective namespaces nodes for a literal result
- * element.
- * @effectiveNs is the set of effective ns-nodes
- * on the literal result element, which will be added to the result
- * element if not already existing in the result tree.
- * This means that excluded namespaces (via exclude-result-prefixes,
- * extension-element-prefixes and the XSLT namespace) not added
- * to the set.
- * Namespace-aliasing was applied on the @effectiveNs.
- */
- static int
- xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
- xsltStyleItemLRElementInfoPtr item,
- xmlNodePtr elem,
- int isLRE)
- {
- xmlNsPtr ns, tmpns;
- xsltEffectiveNsPtr effNs, lastEffNs = NULL;
- int i, j, holdByElem;
- xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
- xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
- if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
- (item == NULL) || (item->effectiveNs != NULL))
- return(-1);
- if (item->inScopeNs == NULL)
- return(0);
- extElemNs = cctxt->inode->extElemNs;
- exclResultNs = cctxt->inode->exclResultNs;
- for (i = 0; i < item->inScopeNs->totalNumber; i++) {
- ns = item->inScopeNs->list[i];
- /*
- * Skip namespaces designated as excluded namespaces
- * -------------------------------------------------
- *
- * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
- * which are target namespaces of namespace-aliases
- * regardless if designated as excluded.
- *
- * Exclude the XSLT namespace.
- */
- if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
- goto skip_ns;
- /*
- * Apply namespace aliasing
- * ------------------------
- *
- * SPEC XSLT 2.0
- * "- A namespace node whose string value is a literal namespace
- * URI is not copied to the result tree.
- * - A namespace node whose string value is a target namespace URI
- * is copied to the result tree, whether or not the URI
- * identifies an excluded namespace."
- *
- * NOTE: The ns-aliasing machanism is non-cascading.
- * (checked with Saxon, Xalan and MSXML .NET).
- * URGENT TODO: is style->nsAliases the effective list of
- * ns-aliases, or do we need to lookup the whole
- * import-tree?
- * TODO: Get rid of import-tree lookup.
- */
- if (cctxt->hasNsAliases) {
- xsltNsAliasPtr alias;
- /*
- * First check for being a target namespace.
- */
- alias = cctxt->nsAliases;
- do {
- /*
- * TODO: Is xmlns="" handled already?
- */
- if ((alias->targetNs != NULL) &&
- (xmlStrEqual(alias->targetNs->href, ns->href)))
- {
- /*
- * Recognized as a target namespace; use it regardless
- * if excluded otherwise.
- */
- goto add_effective_ns;
- }
- alias = alias->next;
- } while (alias != NULL);
- alias = cctxt->nsAliases;
- do {
- /*
- * TODO: Is xmlns="" handled already?
- */
- if ((alias->literalNs != NULL) &&
- (xmlStrEqual(alias->literalNs->href, ns->href)))
- {
- /*
- * Recognized as an namespace alias; do not use it.
- */
- goto skip_ns;
- }
- alias = alias->next;
- } while (alias != NULL);
- }
- /*
- * Exclude excluded result namespaces.
- */
- if (exclResultNs) {
- for (j = 0; j < exclResultNs->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
- goto skip_ns;
- }
- /*
- * Exclude extension-element namespaces.
- */
- if (extElemNs) {
- for (j = 0; j < extElemNs->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
- goto skip_ns;
- }
- add_effective_ns:
- /*
- * OPTIMIZE TODO: This information may not be needed.
- */
- if (isLRE && (elem->nsDef != NULL)) {
- holdByElem = 0;
- tmpns = elem->nsDef;
- do {
- if (tmpns == ns) {
- holdByElem = 1;
- break;
- }
- tmpns = tmpns->next;
- } while (tmpns != NULL);
- } else
- holdByElem = 0;
- /*
- * Add the effective namespace declaration.
- */
- effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
- if (effNs == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error in xsltLREBuildEffectiveNs(): "
- "failed to allocate memory.\n");
- cctxt->style->errors++;
- return(-1);
- }
- if (cctxt->psData->effectiveNs == NULL) {
- cctxt->psData->effectiveNs = effNs;
- effNs->nextInStore = NULL;
- } else {
- effNs->nextInStore = cctxt->psData->effectiveNs;
- cctxt->psData->effectiveNs = effNs;
- }
- effNs->next = NULL;
- effNs->prefix = ns->prefix;
- effNs->nsName = ns->href;
- effNs->holdByElem = holdByElem;
- if (lastEffNs == NULL)
- item->effectiveNs = effNs;
- else
- lastEffNs->next = effNs;
- lastEffNs = effNs;
- skip_ns:
- {}
- }
- return(0);
- }
- /**
- * xsltLREInfoCreate:
- *
- * @isLRE: indicates if the given @elem is a literal result element
- *
- * Creates a new info for a literal result element.
- */
- static int
- xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr elem,
- int isLRE)
- {
- xsltStyleItemLRElementInfoPtr item;
- if ((cctxt == NULL) || (cctxt->inode == NULL))
- return(-1);
- item = (xsltStyleItemLRElementInfoPtr)
- xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
- if (item == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "Internal error in xsltLREInfoCreate(): "
- "memory allocation failed.\n");
- cctxt->style->errors++;
- return(-1);
- }
- memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
- item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
- /*
- * Store it in the stylesheet.
- */
- item->next = cctxt->style->preComps;
- cctxt->style->preComps = (xsltElemPreCompPtr) item;
- /*
- * @inScopeNs are used for execution of XPath expressions
- * in AVTs.
- */
- item->inScopeNs = cctxt->inode->inScopeNs;
- if (elem)
- xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
- cctxt->inode->litResElemInfo = item;
- cctxt->inode->nsChanged = 0;
- cctxt->maxLREs++;
- return(0);
- }
- /**
- * xsltCompilerVarInfoPush:
- * @cctxt: the compilation context
- *
- * Pushes a new var/param info onto the stack.
- *
- * Returns the acquired variable info.
- */
- static xsltVarInfoPtr
- xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr inst,
- const xmlChar *name,
- const xmlChar *nsName)
- {
- xsltVarInfoPtr ivar;
- if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
- ivar = cctxt->ivar->next;
- } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
- ivar = cctxt->ivars;
- } else {
- ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
- if (ivar == NULL) {
- xsltTransformError(NULL, cctxt->style, inst,
- "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
- cctxt->style->errors++;
- return(NULL);
- }
- /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
- if (cctxt->ivars == NULL) {
- cctxt->ivars = ivar;
- ivar->prev = NULL;
- } else {
- cctxt->ivar->next = ivar;
- ivar->prev = cctxt->ivar;
- }
- cctxt->ivar = ivar;
- ivar->next = NULL;
- }
- ivar->depth = cctxt->depth;
- ivar->name = name;
- ivar->nsName = nsName;
- return(ivar);
- }
- /**
- * xsltCompilerVarInfoPop:
- * @cctxt: the compilation context
- *
- * Pops all var/param infos from the stack, which
- * have the current depth.
- */
- static void
- xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
- {
- while ((cctxt->ivar != NULL) &&
- (cctxt->ivar->depth > cctxt->depth))
- {
- cctxt->ivar = cctxt->ivar->prev;
- }
- }
- /*
- * xsltCompilerNodePush:
- *
- * @cctxt: the compilation context
- * @node: the node to be pushed (this can also be the doc-node)
- *
- *
- *
- * Returns the current node info structure or
- * NULL in case of an internal error.
- */
- static xsltCompilerNodeInfoPtr
- xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
- {
- xsltCompilerNodeInfoPtr inode, iprev;
- if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
- inode = cctxt->inode->next;
- } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
- inode = cctxt->inodeList;
- } else {
- /*
- * Create a new node-info.
- */
- inode = (xsltCompilerNodeInfoPtr)
- xmlMalloc(sizeof(xsltCompilerNodeInfo));
- if (inode == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerNodePush: malloc failed.\n");
- return(NULL);
- }
- memset(inode, 0, sizeof(xsltCompilerNodeInfo));
- if (cctxt->inodeList == NULL)
- cctxt->inodeList = inode;
- else {
- cctxt->inodeLast->next = inode;
- inode->prev = cctxt->inodeLast;
- }
- cctxt->inodeLast = inode;
- cctxt->maxNodeInfos++;
- if (cctxt->inode == NULL) {
- cctxt->inode = inode;
- /*
- * Create an initial literal result element info for
- * the root of the stylesheet.
- */
- xsltLREInfoCreate(cctxt, NULL, 0);
- }
- }
- cctxt->depth++;
- cctxt->inode = inode;
- /*
- * REVISIT TODO: Keep the reset always complete.
- * NOTE: Be carefull with the @node, since it might be
- * a doc-node.
- */
- inode->node = node;
- inode->depth = cctxt->depth;
- inode->templ = NULL;
- inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
- inode->type = 0;
- inode->item = NULL;
- inode->curChildType = 0;
- inode->extContentHandled = 0;
- inode->isRoot = 0;
- if (inode->prev != NULL) {
- iprev = inode->prev;
- /*
- * Inherit the following information:
- * ---------------------------------
- *
- * In-scope namespaces
- */
- inode->inScopeNs = iprev->inScopeNs;
- /*
- * Info for literal result elements
- */
- inode->litResElemInfo = iprev->litResElemInfo;
- inode->nsChanged = iprev->nsChanged;
- /*
- * Excluded result namespaces
- */
- inode->exclResultNs = iprev->exclResultNs;
- /*
- * Extension instruction namespaces
- */
- inode->extElemNs = iprev->extElemNs;
- /*
- * Whitespace preservation
- */
- inode->preserveWhitespace = iprev->preserveWhitespace;
- /*
- * Forwards-compatible mode
- */
- inode->forwardsCompat = iprev->forwardsCompat;
- } else {
- inode->inScopeNs = NULL;
- inode->exclResultNs = NULL;
- inode->extElemNs = NULL;
- inode->preserveWhitespace = 0;
- inode->forwardsCompat = 0;
- }
- return(inode);
- }
- /*
- * xsltCompilerNodePop:
- *
- * @cctxt: the compilation context
- * @node: the node to be pushed (this can also be the doc-node)
- *
- * Pops the current node info.
- */
- static void
- xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
- {
- if (cctxt->inode == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Top-node mismatch.\n");
- return;
- }
- /*
- * NOTE: Be carefull with the @node, since it might be
- * a doc-node.
- */
- if (cctxt->inode->node != node) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Node mismatch.\n");
- goto mismatch;
- }
- if (cctxt->inode->depth != cctxt->depth) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Depth mismatch.\n");
- goto mismatch;
- }
- cctxt->depth--;
- /*
- * Pop information of variables.
- */
- if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
- xsltCompilerVarInfoPop(cctxt);
- cctxt->inode = cctxt->inode->prev;
- if (cctxt->inode != NULL)
- cctxt->inode->curChildType = 0;
- return;
- mismatch:
- {
- const xmlChar *nsName = NULL, *name = NULL;
- const xmlChar *infnsName = NULL, *infname = NULL;
- if (node) {
- if (node->type == XML_ELEMENT_NODE) {
- name = node->name;
- if (node->ns != NULL)
- nsName = node->ns->href;
- else
- nsName = BAD_CAST "";
- } else {
- name = BAD_CAST "#document";
- nsName = BAD_CAST "";
- }
- } else
- name = BAD_CAST "Not given";
- if (cctxt->inode->node) {
- if (node->type == XML_ELEMENT_NODE) {
- infname = cctxt->inode->node->name;
- if (cctxt->inode->node->ns != NULL)
- infnsName = cctxt->inode->node->ns->href;
- else
- infnsName = BAD_CAST "";
- } else {
- infname = BAD_CAST "#document";
- infnsName = BAD_CAST "";
- }
- } else
- infname = BAD_CAST "Not given";
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
- name, nsName);
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
- infname, infnsName);
- }
- }
- /*
- * xsltCompilerBuildInScopeNsList:
- *
- * Create and store the list of in-scope namespaces for the given
- * node in the stylesheet. If there are no changes in the in-scope
- * namespaces then the last ns-info of the ancestor axis will be returned.
- * Compilation-time only.
- *
- * Returns the ns-info or NULL if there are no namespaces in scope.
- */
- static xsltNsListContainerPtr
- xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
- {
- xsltNsListContainerPtr nsi = NULL;
- xmlNsPtr *list = NULL, ns;
- int i, maxns = 5;
- /*
- * Create a new ns-list for this position in the node-tree.
- * xmlGetNsList() will return NULL, if there are no ns-decls in the
- * tree. Note that the ns-decl for the XML namespace is not added
- * to the resulting list; the XPath module handles the XML namespace
- * internally.
- */
- while (node != NULL) {
- if (node->type == XML_ELEMENT_NODE) {
- ns = node->nsDef;
- while (ns != NULL) {
- if (nsi == NULL) {
- nsi = (xsltNsListContainerPtr)
- xmlMalloc(sizeof(xsltNsListContainer));
- if (nsi == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: "
- "malloc failed!\n");
- goto internal_err;
- }
- memset(nsi, 0, sizeof(xsltNsListContainer));
- nsi->list =
- (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
- if (nsi->list == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: "
- "malloc failed!\n");
- goto internal_err;
- }
- nsi->list[0] = NULL;
- }
- /*
- * Skip shadowed namespace bindings.
- */
- for (i = 0; i < nsi->totalNumber; i++) {
- if ((ns->prefix == nsi->list[i]->prefix) ||
- (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
- break;
- }
- if (i >= nsi->totalNumber) {
- if (nsi->totalNumber +1 >= maxns) {
- maxns *= 2;
- nsi->list =
- (xmlNsPtr *) xmlRealloc(nsi->list,
- maxns * sizeof(xmlNsPtr));
- if (nsi->list == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: "
- "realloc failed!\n");
- goto internal_err;
- }
- }
- nsi->list[nsi->totalNumber++] = ns;
- nsi->list[nsi->totalNumber] = NULL;
- }
- ns = ns->next;
- }
- }
- node = node->parent;
- }
- if (nsi == NULL)
- return(NULL);
- /*
- * Move the default namespace to last position.
- */
- nsi->xpathNumber = nsi->totalNumber;
- for (i = 0; i < nsi->totalNumber; i++) {
- if (nsi->list[i]->prefix == NULL) {
- ns = nsi->list[i];
- nsi->list[i] = nsi->list[nsi->totalNumber-1];
- nsi->list[nsi->totalNumber-1] = ns;
- nsi->xpathNumber--;
- break;
- }
- }
- /*
- * Store the ns-list in the stylesheet.
- */
- if (xsltPointerListAddSize(
- (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
- (void *) nsi, 5) == -1)
- {
- xmlFree(nsi);
- nsi = NULL;
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
- goto internal_err;
- }
- /*
- * Notify of change in status wrt namespaces.
- */
- if (cctxt->inode != NULL)
- cctxt->inode->nsChanged = 1;
- return(nsi);
- internal_err:
- if (list != NULL)
- xmlFree(list);
- cctxt->style->errors++;
- return(NULL);
- }
- static int
- xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
- xsltPointerListPtr list,
- xmlNodePtr node,
- const xmlChar *value)
- {
- xmlChar *cur, *end;
- xmlNsPtr ns;
- if ((cctxt == NULL) || (value == NULL) || (list == NULL))
- return(-1);
- list->number = 0;
- cur = (xmlChar *) value;
- while (*cur != 0) {
- while (IS_BLANK(*cur)) cur++;
- if (*cur == 0)
- break;
- end = cur;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- cur = xmlStrndup(cur, end - cur);
- if (cur == NULL) {
- cur = end;
- continue;
- }
- /*
- * TODO: Export and use xmlSearchNsByPrefixStrict()
- * in Libxml2, tree.c, since xmlSearchNs() is in most
- * cases not efficient and in some cases not correct.
- *
- * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
- */
- if ((cur[0] == '#') &&
- xmlStrEqual(cur, (const xmlChar *)"#default"))
- ns = xmlSearchNs(cctxt->style->doc, node, NULL);
- else
- ns = xmlSearchNs(cctxt->style->doc, node, cur);
- if (ns == NULL) {
- /*
- * TODO: Better to report the attr-node, otherwise
- * the user won't know which attribute was invalid.
- */
- xsltTransformError(NULL, cctxt->style, node,
- "No namespace binding in scope for prefix '%s'.\n", cur);
- /*
- * XSLT-1.0: "It is an error if there is no namespace
- * bound to the prefix on the element bearing the
- * exclude-result-prefixes or xsl:exclude-result-prefixes
- * attribute."
- */
- cctxt->style->errors++;
- } else {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "resolved prefix '%s'\n", cur);
- #endif
- /*
- * Note that we put the namespace name into the dict.
- */
- if (xsltPointerListAddSize(list,
- (void *) xmlDictLookup(cctxt->style->dict,
- ns->href, -1), 5) == -1)
- {
- xmlFree(cur);
- goto internal_err;
- }
- }
- xmlFree(cur);
- cur = end;
- }
- return(0);
- internal_err:
- cctxt->style->errors++;
- return(-1);
- }
- /**
- * xsltCompilerUtilsCreateMergedList:
- * @dest: the destination list (optional)
- * @first: the first list
- * @second: the second list (optional)
- *
- * Appends the content of @second to @first into @destination.
- * If @destination is NULL a new list will be created.
- *
- * Returns the merged list of items or NULL if there's nothing to merge.
- */
- static xsltPointerListPtr
- xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
- xsltPointerListPtr second)
- {
- xsltPointerListPtr ret;
- size_t num;
- if (first)
- num = first->number;
- else
- num = 0;
- if (second)
- num += second->number;
- if (num == 0)
- return(NULL);
- ret = xsltPointerListCreate(num);
- if (ret == NULL)
- return(NULL);
- /*
- * Copy contents.
- */
- if ((first != NULL) && (first->number != 0)) {
- memcpy(ret->items, first->items,
- first->number * sizeof(void *));
- if ((second != NULL) && (second->number != 0))
- memcpy(ret->items + first->number, second->items,
- second->number * sizeof(void *));
- } else if ((second != NULL) && (second->number != 0))
- memcpy(ret->items, (void *) second->items,
- second->number * sizeof(void *));
- ret->number = num;
- return(ret);
- }
- /*
- * xsltParseExclResultPrefixes:
- *
- * Create and store the list of in-scope namespaces for the given
- * node in the stylesheet. If there are no changes in the in-scope
- * namespaces then the last ns-info of the ancestor axis will be returned.
- * Compilation-time only.
- *
- * Returns the ns-info or NULL if there are no namespaces in scope.
- */
- static xsltPointerListPtr
- xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- xsltPointerListPtr def,
- int instrCategory)
- {
- xsltPointerListPtr list = NULL;
- xmlChar *value;
- xmlAttrPtr attr;
- if ((cctxt == NULL) || (node == NULL))
- return(NULL);
- if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
- else
- attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
- XSLT_NAMESPACE);
- if (attr == NULL)
- return(def);
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Mark the XSLT attr.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
- if ((attr->children != NULL) &&
- (attr->children->content != NULL))
- value = attr->children->content;
- else {
- xsltTransformError(NULL, cctxt->style, node,
- "Attribute 'exclude-result-prefixes': Invalid value.\n");
- cctxt->style->errors++;
- return(def);
- }
- if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
- BAD_CAST value) != 0)
- goto exit;
- if (cctxt->tmpList->number == 0)
- goto exit;
- /*
- * Merge the list with the inherited list.
- */
- list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
- if (list == NULL)
- goto exit;
- /*
- * Store the list in the stylesheet/compiler context.
- */
- if (xsltPointerListAddSize(
- cctxt->psData->exclResultNamespaces, list, 5) == -1)
- {
- xsltPointerListFree(list);
- list = NULL;
- goto exit;
- }
- /*
- * Notify of change in status wrt namespaces.
- */
- if (cctxt->inode != NULL)
- cctxt->inode->nsChanged = 1;
- exit:
- if (list != NULL)
- return(list);
- else
- return(def);
- }
- /*
- * xsltParseExtElemPrefixes:
- *
- * Create and store the list of in-scope namespaces for the given
- * node in the stylesheet. If there are no changes in the in-scope
- * namespaces then the last ns-info of the ancestor axis will be returned.
- * Compilation-time only.
- *
- * Returns the ns-info or NULL if there are no namespaces in scope.
- */
- static xsltPointerListPtr
- xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- xsltPointerListPtr def,
- int instrCategory)
- {
- xsltPointerListPtr list = NULL;
- xmlAttrPtr attr;
- xmlChar *value;
- int i;
- if ((cctxt == NULL) || (node == NULL))
- return(NULL);
- if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
- else
- attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
- XSLT_NAMESPACE);
- if (attr == NULL)
- return(def);
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Mark the XSLT attr.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
- if ((attr->children != NULL) &&
- (attr->children->content != NULL))
- value = attr->children->content;
- else {
- xsltTransformError(NULL, cctxt->style, node,
- "Attribute 'extension-element-prefixes': Invalid value.\n");
- cctxt->style->errors++;
- return(def);
- }
- if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
- BAD_CAST value) != 0)
- goto exit;
- if (cctxt->tmpList->number == 0)
- goto exit;
- /*
- * REVISIT: Register the extension namespaces.
- */
- for (i = 0; i < cctxt->tmpList->number; i++)
- xsltRegisterExtPrefix(cctxt->style, NULL,
- BAD_CAST cctxt->tmpList->items[i]);
- /*
- * Merge the list with the inherited list.
- */
- list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
- if (list == NULL)
- goto exit;
- /*
- * Store the list in the stylesheet.
- */
- if (xsltPointerListAddSize(
- cctxt->psData->extElemNamespaces, list, 5) == -1)
- {
- xsltPointerListFree(list);
- list = NULL;
- goto exit;
- }
- /*
- * Notify of change in status wrt namespaces.
- */
- if (cctxt->inode != NULL)
- cctxt->inode->nsChanged = 1;
- exit:
- if (list != NULL)
- return(list);
- else
- return(def);
- }
- /*
- * xsltParseAttrXSLTVersion:
- *
- * @cctxt: the compilation context
- * @node: the element-node
- * @isXsltElem: whether this is an XSLT element
- *
- * Parses the attribute xsl:version.
- *
- * Returns 1 if there was such an attribute, 0 if not and
- * -1 if an internal or API error occured.
- */
- static int
- xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- int instrCategory)
- {
- xmlChar *value;
- xmlAttrPtr attr;
- if ((cctxt == NULL) || (node == NULL))
- return(-1);
- if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
- else
- attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
- if (attr == NULL)
- return(0);
- attr->psvi = (void *) xsltXSLTAttrMarker;
- if ((attr->children != NULL) &&
- (attr->children->content != NULL))
- value = attr->children->content;
- else {
- xsltTransformError(NULL, cctxt->style, node,
- "Attribute 'version': Invalid value.\n");
- cctxt->style->errors++;
- return(1);
- }
- if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
- cctxt->inode->forwardsCompat = 1;
- /*
- * TODO: To what extent do we support the
- * forwards-compatible mode?
- */
- /*
- * Report this only once per compilation episode.
- */
- if (! cctxt->hasForwardsCompat) {
- cctxt->hasForwardsCompat = 1;
- cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
- xsltTransformError(NULL, cctxt->style, node,
- "Warning: the attribute xsl:version specifies a value "
- "different from '1.0'. Switching to forwards-compatible "
- "mode. Only features of XSLT 1.0 are supported by this "
- "processor.\n");
- cctxt->style->warnings++;
- cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
- }
- } else {
- cctxt->inode->forwardsCompat = 0;
- }
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Set a marker on XSLT attributes.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
- return(1);
- }
- static int
- xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
- {
- xmlNodePtr deleteNode, cur, txt, textNode = NULL;
- xmlDocPtr doc;
- xsltStylesheetPtr style;
- int internalize = 0, findSpaceAttr;
- int xsltStylesheetElemDepth;
- xmlAttrPtr attr;
- xmlChar *value;
- const xmlChar *name, *nsNameXSLT = NULL;
- int strictWhitespace, inXSLText = 0;
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- xsltNsMapPtr nsMapItem;
- #endif
- if ((cctxt == NULL) || (cctxt->style == NULL) ||
- (node == NULL) || (node->type != XML_ELEMENT_NODE))
- return(-1);
- doc = node->doc;
- if (doc == NULL)
- goto internal_err;
- style = cctxt->style;
- if ((style->dict != NULL) && (doc->dict == style->dict))
- internalize = 1;
- else
- style->internalized = 0;
- /*
- * Init value of xml:space. Since this might be an embedded
- * stylesheet, this is needed to be performed on the element
- * where the stylesheet is rooted at, taking xml:space of
- * ancestors into account.
- */
- if (! cctxt->simplified)
- xsltStylesheetElemDepth = cctxt->depth +1;
- else
- xsltStylesheetElemDepth = 0;
- if (xmlNodeGetSpacePreserve(node) != 1)
- cctxt->inode->preserveWhitespace = 0;
- else
- cctxt->inode->preserveWhitespace = 1;
- /*
- * Eval if we should keep the old incorrect behaviour.
- */
- strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
- nsNameXSLT = xsltConstNamespaceNameXSLT;
- deleteNode = NULL;
- cur = node;
- while (cur != NULL) {
- if (deleteNode != NULL) {
- #ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParsePreprocessStylesheetTree: removing node\n");
- #endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- if (cur->type == XML_ELEMENT_NODE) {
- /*
- * Clear the PSVI field.
- */
- cur->psvi = NULL;
- xsltCompilerNodePush(cctxt, cur);
- inXSLText = 0;
- textNode = NULL;
- findSpaceAttr = 1;
- cctxt->inode->stripWhitespace = 0;
- /*
- * TODO: I'd love to use a string pointer comparison here :-/
- */
- if (IS_XSLT_ELEM(cur)) {
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- if (cur->ns->href != nsNameXSLT) {
- nsMapItem = xsltNewNamespaceMapItem(cctxt,
- doc, cur->ns, cur);
- if (nsMapItem == NULL)
- goto internal_err;
- cur->ns->href = nsNameXSLT;
- }
- #endif
- if (cur->name == NULL)
- goto process_attributes;
- /*
- * Mark the XSLT element for later recognition.
- * TODO: Using the marker is still too dangerous, since if
- * the parsing mechanism leaves out an XSLT element, then
- * this might hit the transformation-mechanism, which
- * will break if it doesn't expect such a marker.
- */
- /* cur->psvi = (void *) xsltXSLTElemMarker; */
- /*
- * XSLT 2.0: "Any whitespace text node whose parent is
- * one of the following elements is removed from the "
- * tree, regardless of any xml:space attributes:..."
- * xsl:apply-imports,
- * xsl:apply-templates,
- * xsl:attribute-set,
- * xsl:call-template,
- * xsl:choose,
- * xsl:stylesheet, xsl:transform.
- * XSLT 2.0: xsl:analyze-string,
- * xsl:character-map,
- * xsl:next-match
- *
- * TODO: I'd love to use a string pointer comparison here :-/
- */
- name = cur->name;
- switch (*name) {
- case 't':
- if ((name[0] == 't') && (name[1] == 'e') &&
- (name[2] == 'x') && (name[3] == 't') &&
- (name[4] == 0))
- {
- /*
- * Process the xsl:text element.
- * ----------------------------
- * Mark it for later recognition.
- */
- cur->psvi = (void *) xsltXSLTTextMarker;
- /*
- * For stylesheets, the set of
- * whitespace-preserving element names
- * consists of just xsl:text.
- */
- findSpaceAttr = 0;
- cctxt->inode->preserveWhitespace = 1;
- inXSLText = 1;
- }
- break;
- case 'c':
- if (xmlStrEqual(name, BAD_CAST "choose") ||
- xmlStrEqual(name, BAD_CAST "call-template"))
- cctxt->inode->stripWhitespace = 1;
- break;
- case 'a':
- if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
- xmlStrEqual(name, BAD_CAST "apply-imports") ||
- xmlStrEqual(name, BAD_CAST "attribute-set"))
- cctxt->inode->stripWhitespace = 1;
- break;
- default:
- if (xsltStylesheetElemDepth == cctxt->depth) {
- /*
- * This is a xsl:stylesheet/xsl:transform.
- */
- cctxt->inode->stripWhitespace = 1;
- break;
- }
- if ((cur->prev != NULL) &&
- (cur->prev->type == XML_TEXT_NODE))
- {
- /*
- * XSLT 2.0 : "Any whitespace text node whose
- * following-sibling node is an xsl:param or
- * xsl:sort element is removed from the tree,
- * regardless of any xml:space attributes."
- */
- if (((*name == 'p') || (*name == 's')) &&
- (xmlStrEqual(name, BAD_CAST "param") ||
- xmlStrEqual(name, BAD_CAST "sort")))
- {
- do {
- if (IS_BLANK_NODE(cur->prev)) {
- txt = cur->prev;
- xmlUnlinkNode(txt);
- xmlFreeNode(txt);
- } else {
- /*
- * This will result in a content
- * error, when hitting the parsing
- * functions.
- */
- break;
- }
- } while (cur->prev);
- }
- }
- break;
- }
- }
- process_attributes:
- /*
- * Process attributes.
- * ------------------
- */
- if (cur->properties != NULL) {
- if (cur->children == NULL)
- findSpaceAttr = 0;
- attr = cur->properties;
- do {
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
- xmlStrEqual(attr->ns->href, nsNameXSLT))
- {
- nsMapItem = xsltNewNamespaceMapItem(cctxt,
- doc, attr->ns, cur);
- if (nsMapItem == NULL)
- goto internal_err;
- attr->ns->href = nsNameXSLT;
- }
- #endif
- if (internalize) {
- /*
- * Internalize the attribute's value; the goal is to
- * speed up operations and minimize used space by
- * compiled stylesheets.
- */
- txt = attr->children;
- /*
- * NOTE that this assumes only one
- * text-node in the attribute's content.
- */
- if ((txt != NULL) && (txt->content != NULL) &&
- (!xmlDictOwns(style->dict, txt->content)))
- {
- value = (xmlChar *) xmlDictLookup(style->dict,
- txt->content, -1);
- xmlNodeSetContent(txt, NULL);
- txt->content = value;
- }
- }
- /*
- * Process xml:space attributes.
- * ----------------------------
- */
- if ((findSpaceAttr != 0) &&
- (attr->ns != NULL) &&
- (attr->name != NULL) &&
- (attr->name[0] == 's') &&
- (attr->ns->prefix != NULL) &&
- (attr->ns->prefix[0] == 'x') &&
- (attr->ns->prefix[1] == 'm') &&
- (attr->ns->prefix[2] == 'l') &&
- (attr->ns->prefix[3] == 0))
- {
- value = xmlGetNsProp(cur, BAD_CAST "space",
- XML_XML_NAMESPACE);
- if (value != NULL) {
- if (xmlStrEqual(value, BAD_CAST "preserve")) {
- cctxt->inode->preserveWhitespace = 1;
- } else if (xmlStrEqual(value, BAD_CAST "default")) {
- cctxt->inode->preserveWhitespace = 0;
- } else {
- /* Invalid value for xml:space. */
- xsltTransformError(NULL, style, cur,
- "Attribute xml:space: Invalid value.\n");
- cctxt->style->warnings++;
- }
- findSpaceAttr = 0;
- xmlFree(value);
- }
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- /*
- * We'll descend into the children of element nodes only.
- */
- if (cur->children != NULL) {
- cur = cur->children;
- continue;
- }
- } else if ((cur->type == XML_TEXT_NODE) ||
- (cur->type == XML_CDATA_SECTION_NODE))
- {
- /*
- * Merge adjacent text/CDATA-section-nodes
- * ---------------------------------------
- * In order to avoid breaking of existing stylesheets,
- * if the old behaviour is wanted (strictWhitespace == 0),
- * then we *won't* merge adjacent text-nodes
- * (except in xsl:text); this will ensure that whitespace-only
- * text nodes are (incorrectly) not stripped in some cases.
- *
- * Example: : <foo> <!-- bar -->zoo</foo>
- * Corrent (strict) result: <foo> zoo</foo>
- * Incorrect (old) result : <foo>zoo</foo>
- *
- * NOTE that we *will* merge adjacent text-nodes if
- * they are in xsl:text.
- * Example, the following:
- * <xsl:text> <!-- bar -->zoo<xsl:text>
- * will result in both cases in:
- * <xsl:text> zoo<xsl:text>
- */
- cur->type = XML_TEXT_NODE;
- if ((strictWhitespace != 0) || (inXSLText != 0)) {
- /*
- * New behaviour; merge nodes.
- */
- if (textNode == NULL)
- textNode = cur;
- else {
- if (cur->content != NULL)
- xmlNodeAddContent(textNode, cur->content);
- deleteNode = cur;
- }
- if ((cur->next == NULL) ||
- (cur->next->type == XML_ELEMENT_NODE))
- goto end_of_text;
- else
- goto next_sibling;
- } else {
- /*
- * Old behaviour.
- */
- if (textNode == NULL)
- textNode = cur;
- goto end_of_text;
- }
- } else if ((cur->type == XML_COMMENT_NODE) ||
- (cur->type == XML_PI_NODE))
- {
- /*
- * Remove processing instructions and comments.
- */
- deleteNode = cur;
- if ((cur->next == NULL) ||
- (cur->next->type == XML_ELEMENT_NODE))
- goto end_of_text;
- else
- goto next_sibling;
- } else {
- textNode = NULL;
- /*
- * Invalid node-type for this data-model.
- */
- xsltTransformError(NULL, style, cur,
- "Invalid type of node for the XSLT data model.\n");
- cctxt->style->errors++;
- goto next_sibling;
- }
- end_of_text:
- if (textNode) {
- value = textNode->content;
- /*
- * At this point all adjacent text/CDATA-section nodes
- * have been merged.
- *
- * Strip whitespace-only text-nodes.
- * (cctxt->inode->stripWhitespace)
- */
- if ((value == NULL) || (*value == 0) ||
- (((cctxt->inode->stripWhitespace) ||
- (! cctxt->inode->preserveWhitespace)) &&
- IS_BLANK(*value) &&
- xsltIsBlank(value)))
- {
- if (textNode != cur) {
- xmlUnlinkNode(textNode);
- xmlFreeNode(textNode);
- } else
- deleteNode = textNode;
- textNode = NULL;
- goto next_sibling;
- }
- /*
- * Convert CDATA-section nodes to text-nodes.
- * TODO: Can this produce problems?
- */
- if (textNode->type != XML_TEXT_NODE) {
- textNode->type = XML_TEXT_NODE;
- textNode->name = xmlStringText;
- }
- if (internalize &&
- (textNode->content != NULL) &&
- (!xmlDictOwns(style->dict, textNode->content)))
- {
- /*
- * Internalize the string.
- */
- value = (xmlChar *) xmlDictLookup(style->dict,
- textNode->content, -1);
- xmlNodeSetContent(textNode, NULL);
- textNode->content = value;
- }
- textNode = NULL;
- /*
- * Note that "disable-output-escaping" of the xsl:text
- * element will be applied at a later level, when
- * XSLT elements are processed.
- */
- }
- next_sibling:
- if (cur->type == XML_ELEMENT_NODE) {
- xsltCompilerNodePop(cctxt, cur);
- }
- if (cur == node)
- break;
- if (cur->next != NULL) {
- cur = cur->next;
- } else {
- cur = cur->parent;
- inXSLText = 0;
- goto next_sibling;
- };
- }
- if (deleteNode != NULL) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParsePreprocessStylesheetTree: removing node\n");
- #endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- }
- return(0);
- internal_err:
- return(-1);
- }
- #endif /* XSLT_REFACTORED */
- #ifdef XSLT_REFACTORED
- #else
- static void
- xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
- {
- xmlNodePtr deleteNode, styleelem;
- int internalize = 0;
- if ((style == NULL) || (cur == NULL))
- return;
- if ((cur->doc != NULL) && (style->dict != NULL) &&
- (cur->doc->dict == style->dict))
- internalize = 1;
- else
- style->internalized = 0;
- if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
- (IS_XSLT_NAME(cur, "stylesheet"))) {
- styleelem = cur;
- } else {
- styleelem = NULL;
- }
- /*
- * This content comes from the stylesheet
- * For stylesheets, the set of whitespace-preserving
- * element names consists of just xsl:text.
- */
- deleteNode = NULL;
- while (cur != NULL) {
- if (deleteNode != NULL) {
- #ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltPreprocessStylesheet: removing ignorable blank node\n");
- #endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- if (cur->type == XML_ELEMENT_NODE) {
- int exclPrefixes;
- /*
- * Internalize attributes values.
- */
- if ((internalize) && (cur->properties != NULL)) {
- xmlAttrPtr attr = cur->properties;
- xmlNodePtr txt;
- while (attr != NULL) {
- txt = attr->children;
- if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
- (txt->content != NULL) &&
- (!xmlDictOwns(style->dict, txt->content)))
- {
- xmlChar *tmp;
- /*
- * internalize the text string, goal is to speed
- * up operations and minimize used space by compiled
- * stylesheets.
- */
- tmp = (xmlChar *) xmlDictLookup(style->dict,
- txt->content, -1);
- if (tmp != txt->content) {
- xmlNodeSetContent(txt, NULL);
- txt->content = tmp;
- }
- }
- attr = attr->next;
- }
- }
- if (IS_XSLT_ELEM(cur)) {
- exclPrefixes = 0;
- if (IS_XSLT_NAME(cur, "text")) {
- for (;exclPrefixes > 0;exclPrefixes--)
- exclPrefixPop(style);
- goto skip_children;
- }
- } else {
- exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
- }
- if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
- xmlNsPtr ns = cur->nsDef, prev = NULL, next;
- xmlNodePtr root = NULL;
- int i, moved;
- root = xmlDocGetRootElement(cur->doc);
- if ((root != NULL) && (root != cur)) {
- while (ns != NULL) {
- moved = 0;
- next = ns->next;
- for (i = 0;i < style->exclPrefixNr;i++) {
- if ((ns->prefix != NULL) &&
- (xmlStrEqual(ns->href,
- style->exclPrefixTab[i]))) {
- /*
- * Move the namespace definition on the root
- * element to avoid duplicating it without
- * loosing it.
- */
- if (prev == NULL) {
- cur->nsDef = ns->next;
- } else {
- prev->next = ns->next;
- }
- ns->next = root->nsDef;
- root->nsDef = ns;
- moved = 1;
- break;
- }
- }
- if (moved == 0)
- prev = ns;
- ns = next;
- }
- }
- }
- /*
- * If we have prefixes locally, recurse and pop them up when
- * going back
- */
- if (exclPrefixes > 0) {
- xsltPreprocessStylesheet(style, cur->children);
- for (;exclPrefixes > 0;exclPrefixes--)
- exclPrefixPop(style);
- goto skip_children;
- }
- } else if (cur->type == XML_TEXT_NODE) {
- if (IS_BLANK_NODE(cur)) {
- if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
- deleteNode = cur;
- }
- } else if ((cur->content != NULL) && (internalize) &&
- (!xmlDictOwns(style->dict, cur->content))) {
- xmlChar *tmp;
- /*
- * internalize the text string, goal is to speed
- * up operations and minimize used space by compiled
- * stylesheets.
- */
- tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
- xmlNodeSetContent(cur, NULL);
- cur->content = tmp;
- }
- } else if ((cur->type != XML_ELEMENT_NODE) &&
- (cur->type != XML_CDATA_SECTION_NODE)) {
- deleteNode = cur;
- goto skip_children;
- }
- /*
- * Skip to next node. In case of a namespaced element children of
- * the stylesheet and not in the XSLT namespace and not an extension
- * element, ignore its content.
- */
- if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
- (styleelem != NULL) && (cur->parent == styleelem) &&
- (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
- (!xsltCheckExtURI(style, cur->ns->href))) {
- goto skip_children;
- } else if (cur->children != NULL) {
- if ((cur->children->type != XML_ENTITY_DECL) &&
- (cur->children->type != XML_ENTITY_REF_NODE) &&
- (cur->children->type != XML_ENTITY_NODE)) {
- cur = cur->children;
- continue;
- }
- }
- skip_children:
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
- do {
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == (xmlNodePtr) style->doc) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- if (deleteNode != NULL) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltPreprocessStylesheet: removing ignorable blank node\n");
- #endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- }
- }
- #endif /* end of else XSLT_REFACTORED */
- /**
- * xsltGatherNamespaces:
- * @style: the XSLT stylesheet
- *
- * Browse the stylesheet and build the namspace hash table which
- * will be used for XPath interpretation. If needed do a bit of normalization
- */
- static void
- xsltGatherNamespaces(xsltStylesheetPtr style) {
- xmlNodePtr cur;
- const xmlChar *URI;
- if (style == NULL)
- return;
- /*
- * TODO: basically if the stylesheet uses the same prefix for different
- * patterns, well they may be in problem, hopefully they will get
- * a warning first.
- */
- /*
- * TODO: Eliminate the use of the hash for XPath expressions.
- * An expression should be evaluated in the context of the in-scope
- * namespaces; eliminate the restriction of an XML document to contain
- * no duplicate prefixes for different namespace names.
- *
- */
- cur = xmlDocGetRootElement(style->doc);
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE) {
- xmlNsPtr ns = cur->nsDef;
- while (ns != NULL) {
- if (ns->prefix != NULL) {
- if (style->nsHash == NULL) {
- style->nsHash = xmlHashCreate(10);
- if (style->nsHash == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltGatherNamespaces: failed to create hash table\n");
- style->errors++;
- return;
- }
- }
- URI = xmlHashLookup(style->nsHash, ns->prefix);
- if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
- xsltTransformError(NULL, style, cur,
- "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
- style->warnings++;
- } else if (URI == NULL) {
- xmlHashUpdateEntry(style->nsHash, ns->prefix,
- (void *) ns->href, NULL);
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
- #endif
- }
- }
- ns = ns->next;
- }
- }
- /*
- * Skip to next node
- */
- if (cur->children != NULL) {
- if (cur->children->type != XML_ENTITY_DECL) {
- cur = cur->children;
- continue;
- }
- }
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
- do {
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == (xmlNodePtr) style->doc) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- }
- #ifdef XSLT_REFACTORED
- static xsltStyleType
- xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node)
- {
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
- (node->name == NULL))
- return(0);
- if (node->name[0] == 'a') {
- if (IS_XSLT_NAME(node, "apply-templates"))
- return(XSLT_FUNC_APPLYTEMPLATES);
- else if (IS_XSLT_NAME(node, "attribute"))
- return(XSLT_FUNC_ATTRIBUTE);
- else if (IS_XSLT_NAME(node, "apply-imports"))
- return(XSLT_FUNC_APPLYIMPORTS);
- else if (IS_XSLT_NAME(node, "attribute-set"))
- return(0);
- } else if (node->name[0] == 'c') {
- if (IS_XSLT_NAME(node, "choose"))
- return(XSLT_FUNC_CHOOSE);
- else if (IS_XSLT_NAME(node, "copy"))
- return(XSLT_FUNC_COPY);
- else if (IS_XSLT_NAME(node, "copy-of"))
- return(XSLT_FUNC_COPYOF);
- else if (IS_XSLT_NAME(node, "call-template"))
- return(XSLT_FUNC_CALLTEMPLATE);
- else if (IS_XSLT_NAME(node, "comment"))
- return(XSLT_FUNC_COMMENT);
- } else if (node->name[0] == 'd') {
- if (IS_XSLT_NAME(node, "document"))
- return(XSLT_FUNC_DOCUMENT);
- else if (IS_XSLT_NAME(node, "decimal-format"))
- return(0);
- } else if (node->name[0] == 'e') {
- if (IS_XSLT_NAME(node, "element"))
- return(XSLT_FUNC_ELEMENT);
- } else if (node->name[0] == 'f') {
- if (IS_XSLT_NAME(node, "for-each"))
- return(XSLT_FUNC_FOREACH);
- else if (IS_XSLT_NAME(node, "fallback"))
- return(XSLT_FUNC_FALLBACK);
- } else if (*(node->name) == 'i') {
- if (IS_XSLT_NAME(node, "if"))
- return(XSLT_FUNC_IF);
- else if (IS_XSLT_NAME(node, "include"))
- return(0);
- else if (IS_XSLT_NAME(node, "import"))
- return(0);
- } else if (*(node->name) == 'k') {
- if (IS_XSLT_NAME(node, "key"))
- return(0);
- } else if (*(node->name) == 'm') {
- if (IS_XSLT_NAME(node, "message"))
- return(XSLT_FUNC_MESSAGE);
- } else if (*(node->name) == 'n') {
- if (IS_XSLT_NAME(node, "number"))
- return(XSLT_FUNC_NUMBER);
- else if (IS_XSLT_NAME(node, "namespace-alias"))
- return(0);
- } else if (*(node->name) == 'o') {
- if (IS_XSLT_NAME(node, "otherwise"))
- return(XSLT_FUNC_OTHERWISE);
- else if (IS_XSLT_NAME(node, "output"))
- return(0);
- } else if (*(node->name) == 'p') {
- if (IS_XSLT_NAME(node, "param"))
- return(XSLT_FUNC_PARAM);
- else if (IS_XSLT_NAME(node, "processing-instruction"))
- return(XSLT_FUNC_PI);
- else if (IS_XSLT_NAME(node, "preserve-space"))
- return(0);
- } else if (*(node->name) == 's') {
- if (IS_XSLT_NAME(node, "sort"))
- return(XSLT_FUNC_SORT);
- else if (IS_XSLT_NAME(node, "strip-space"))
- return(0);
- else if (IS_XSLT_NAME(node, "stylesheet"))
- return(0);
- } else if (node->name[0] == 't') {
- if (IS_XSLT_NAME(node, "text"))
- return(XSLT_FUNC_TEXT);
- else if (IS_XSLT_NAME(node, "template"))
- return(0);
- else if (IS_XSLT_NAME(node, "transform"))
- return(0);
- } else if (*(node->name) == 'v') {
- if (IS_XSLT_NAME(node, "value-of"))
- return(XSLT_FUNC_VALUEOF);
- else if (IS_XSLT_NAME(node, "variable"))
- return(XSLT_FUNC_VARIABLE);
- } else if (*(node->name) == 'w') {
- if (IS_XSLT_NAME(node, "when"))
- return(XSLT_FUNC_WHEN);
- if (IS_XSLT_NAME(node, "with-param"))
- return(XSLT_FUNC_WITHPARAM);
- }
- return(0);
- }
- /**
- * xsltParseAnyXSLTElem:
- *
- * @cctxt: the compilation context
- * @elem: the element node of the XSLT instruction
- *
- * Parses, validates the content models and compiles XSLT instructions.
- *
- * Returns 0 if everything's fine;
- * -1 on API or internal errors.
- */
- int
- xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
- {
- if ((cctxt == NULL) || (elem == NULL) ||
- (elem->type != XML_ELEMENT_NODE))
- return(-1);
- elem->psvi = NULL;
- if (! (IS_XSLT_ELEM_FAST(elem)))
- return(-1);
- /*
- * Detection of handled content of extension instructions.
- */
- if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- cctxt->inode->extContentHandled = 1;
- }
- xsltCompilerNodePush(cctxt, elem);
- /*
- * URGENT TODO: Find a way to speed up this annoying redundant
- * textual node-name and namespace comparison.
- */
- if (cctxt->inode->prev->curChildType != 0)
- cctxt->inode->type = cctxt->inode->prev->curChildType;
- else
- cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
- /*
- * Update the in-scope namespaces if needed.
- */
- if (elem->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, elem);
- /*
- * xsltStylePreCompute():
- * This will compile the information found on the current
- * element's attributes. NOTE that this won't process the
- * children of the instruction.
- */
- xsltStylePreCompute(cctxt->style, elem);
- /*
- * TODO: How to react on errors in xsltStylePreCompute() ?
- */
- /*
- * Validate the content model of the XSLT-element.
- */
- switch (cctxt->inode->type) {
- case XSLT_FUNC_APPLYIMPORTS:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_APPLYTEMPLATES:
- /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
- goto apply_templates;
- case XSLT_FUNC_ATTRIBUTE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_CALLTEMPLATE:
- /* <!-- Content: xsl:with-param* --> */
- goto call_template;
- case XSLT_FUNC_CHOOSE:
- /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
- goto choose;
- case XSLT_FUNC_COMMENT:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_COPY:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_COPYOF:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_DOCUMENT: /* Extra one */
- /* ?? template ?? */
- goto sequence_constructor;
- case XSLT_FUNC_ELEMENT:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_FALLBACK:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_FOREACH:
- /* <!-- Content: (xsl:sort*, template) --> */
- goto for_each;
- case XSLT_FUNC_IF:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_OTHERWISE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_MESSAGE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_NUMBER:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_PARAM:
- /*
- * Check for redefinition.
- */
- if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
- xsltVarInfoPtr ivar = cctxt->ivar;
- do {
- if ((ivar->name ==
- ((xsltStyleItemParamPtr) elem->psvi)->name) &&
- (ivar->nsName ==
- ((xsltStyleItemParamPtr) elem->psvi)->ns))
- {
- elem->psvi = NULL;
- xsltTransformError(NULL, cctxt->style, elem,
- "Redefinition of variable or parameter '%s'.\n",
- ivar->name);
- cctxt->style->errors++;
- goto error;
- }
- ivar = ivar->prev;
- } while (ivar != NULL);
- }
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_PI:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_SORT:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_TEXT:
- /* <!-- Content: #PCDATA --> */
- goto text;
- case XSLT_FUNC_VALUEOF:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_VARIABLE:
- /*
- * Check for redefinition.
- */
- if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
- xsltVarInfoPtr ivar = cctxt->ivar;
- do {
- if ((ivar->name ==
- ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
- (ivar->nsName ==
- ((xsltStyleItemVariablePtr) elem->psvi)->ns))
- {
- elem->psvi = NULL;
- xsltTransformError(NULL, cctxt->style, elem,
- "Redefinition of variable or parameter '%s'.\n",
- ivar->name);
- cctxt->style->errors++;
- goto error;
- }
- ivar = ivar->prev;
- } while (ivar != NULL);
- }
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_WHEN:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_WITHPARAM:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- default:
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
- elem->name);
- #endif
- xsltTransformError(NULL, cctxt->style, elem,
- "xsltParseXSLTNode: Internal error; "
- "unhandled XSLT element '%s'.\n", elem->name);
- cctxt->style->errors++;
- goto internal_err;
- }
- apply_templates:
- /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- do {
- if (child->type == XML_ELEMENT_NODE) {
- if (IS_XSLT_ELEM_FAST(child)) {
- if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
- cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
- xsltParseAnyXSLTElem(cctxt, child);
- } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
- cctxt->inode->curChildType = XSLT_FUNC_SORT;
- xsltParseAnyXSLTElem(cctxt, child);
- } else
- xsltParseContentError(cctxt->style, child);
- } else
- xsltParseContentError(cctxt->style, child);
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
- call_template:
- /* <!-- Content: xsl:with-param* --> */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- do {
- if (child->type == XML_ELEMENT_NODE) {
- if (IS_XSLT_ELEM_FAST(child)) {
- xsltStyleType type;
- type = xsltGetXSLTElementTypeByNode(cctxt, child);
- if (type == XSLT_FUNC_WITHPARAM) {
- cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
- xsltParseAnyXSLTElem(cctxt, child);
- } else {
- xsltParseContentError(cctxt->style, child);
- }
- } else
- xsltParseContentError(cctxt->style, child);
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
- text:
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- do {
- if ((child->type != XML_TEXT_NODE) &&
- (child->type != XML_CDATA_SECTION_NODE))
- {
- xsltTransformError(NULL, cctxt->style, elem,
- "The XSLT 'text' element must have only character "
- "data as content.\n");
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
- empty_content:
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- /*
- * Relaxed behaviour: we will allow whitespace-only text-nodes.
- */
- do {
- if (((child->type != XML_TEXT_NODE) &&
- (child->type != XML_CDATA_SECTION_NODE)) ||
- (! IS_BLANK_NODE(child)))
- {
- xsltTransformError(NULL, cctxt->style, elem,
- "This XSLT element must have no content.\n");
- cctxt->style->errors++;
- break;
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
- choose:
- /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
- /*
- * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
- * The old behaviour did not check this.
- * NOTE: In XSLT 2.0 they are stripped beforehand
- * if whitespace-only (regardless of xml:space).
- */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- int nbWhen = 0, nbOtherwise = 0, err = 0;
- do {
- if (child->type == XML_ELEMENT_NODE) {
- if (IS_XSLT_ELEM_FAST(child)) {
- xsltStyleType type;
- type = xsltGetXSLTElementTypeByNode(cctxt, child);
- if (type == XSLT_FUNC_WHEN) {
- nbWhen++;
- if (nbOtherwise) {
- xsltParseContentError(cctxt->style, child);
- err = 1;
- break;
- }
- cctxt->inode->curChildType = XSLT_FUNC_WHEN;
- xsltParseAnyXSLTElem(cctxt, child);
- } else if (type == XSLT_FUNC_OTHERWISE) {
- if (! nbWhen) {
- xsltParseContentError(cctxt->style, child);
- err = 1;
- break;
- }
- if (nbOtherwise) {
- xsltTransformError(NULL, cctxt->style, elem,
- "The XSLT 'choose' element must not contain "
- "more than one XSLT 'otherwise' element.\n");
- cctxt->style->errors++;
- err = 1;
- break;
- }
- nbOtherwise++;
- cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
- xsltParseAnyXSLTElem(cctxt, child);
- } else
- xsltParseContentError(cctxt->style, child);
- } else
- xsltParseContentError(cctxt->style, child);
- }
- /*
- else
- xsltParseContentError(cctxt, child);
- */
- child = child->next;
- } while (child != NULL);
- if ((! err) && (! nbWhen)) {
- xsltTransformError(NULL, cctxt->style, elem,
- "The XSLT element 'choose' must contain at least one "
- "XSLT element 'when'.\n");
- cctxt->style->errors++;
- }
- }
- goto exit;
- for_each:
- /* <!-- Content: (xsl:sort*, template) --> */
- /*
- * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
- * The old behaviour did not allow this, but it catched this
- * only at transformation-time.
- * In XSLT 2.0 they are stripped beforehand if whitespace-only
- * (regardless of xml:space).
- */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- /*
- * Parse xsl:sort first.
- */
- do {
- if ((child->type == XML_ELEMENT_NODE) &&
- IS_XSLT_ELEM_FAST(child))
- {
- if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
- XSLT_FUNC_SORT)
- {
- cctxt->inode->curChildType = XSLT_FUNC_SORT;
- xsltParseAnyXSLTElem(cctxt, child);
- } else
- break;
- } else
- break;
- child = child->next;
- } while (child != NULL);
- /*
- * Parse the sequece constructor.
- */
- if (child != NULL)
- xsltParseSequenceConstructor(cctxt, child);
- }
- goto exit;
- sequence_constructor:
- /*
- * Parse the sequence constructor.
- */
- if (elem->children != NULL)
- xsltParseSequenceConstructor(cctxt, elem->children);
- /*
- * Register information for vars/params. Only needed if there
- * are any following siblings.
- */
- if ((elem->next != NULL) &&
- ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
- (cctxt->inode->type == XSLT_FUNC_PARAM)))
- {
- if ((elem->psvi != NULL) &&
- (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
- {
- xsltCompilerVarInfoPush(cctxt, elem,
- ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
- ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
- }
- }
- error:
- exit:
- xsltCompilerNodePop(cctxt, elem);
- return(0);
- internal_err:
- xsltCompilerNodePop(cctxt, elem);
- return(-1);
- }
- /**
- * xsltForwardsCompatUnkownItemCreate:
- *
- * @cctxt: the compilation context
- *
- * Creates a compiled representation of the unknown
- * XSLT instruction.
- *
- * Returns the compiled representation.
- */
- static xsltStyleItemUknownPtr
- xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
- {
- xsltStyleItemUknownPtr item;
- item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
- if (item == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "Internal error in xsltForwardsCompatUnkownItemCreate(): "
- "Failed to allocate memory.\n");
- cctxt->style->errors++;
- return(NULL);
- }
- memset(item, 0, sizeof(xsltStyleItemUknown));
- item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
- /*
- * Store it in the stylesheet.
- */
- item->next = cctxt->style->preComps;
- cctxt->style->preComps = (xsltElemPreCompPtr) item;
- return(item);
- }
- /**
- * xsltParseUnknownXSLTElem:
- *
- * @cctxt: the compilation context
- * @node: the element of the unknown XSLT instruction
- *
- * Parses an unknown XSLT element.
- * If forwards compatible mode is enabled this will allow
- * such an unknown XSLT and; otherwise it is rejected.
- *
- * Returns 1 in the unknown XSLT instruction is rejected,
- * 0 if everything's fine and
- * -1 on API or internal errors.
- */
- static int
- xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node)
- {
- if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
- return(-1);
- /*
- * Detection of handled content of extension instructions.
- */
- if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- cctxt->inode->extContentHandled = 1;
- }
- if (cctxt->inode->forwardsCompat == 0) {
- /*
- * We are not in forwards-compatible mode, so raise an error.
- */
- xsltTransformError(NULL, cctxt->style, node,
- "Unknown XSLT element '%s'.\n", node->name);
- cctxt->style->errors++;
- return(1);
- }
- /*
- * Forwards-compatible mode.
- * ------------------------
- *
- * Parse/compile xsl:fallback elements.
- *
- * QUESTION: Do we have to raise an error if there's no xsl:fallback?
- * ANSWER: No, since in the stylesheet the fallback behaviour might
- * also be provided by using the XSLT function "element-available".
- */
- if (cctxt->unknownItem == NULL) {
- /*
- * Create a singleton for all unknown XSLT instructions.
- */
- cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
- if (cctxt->unknownItem == NULL) {
- node->psvi = NULL;
- return(-1);
- }
- }
- node->psvi = cctxt->unknownItem;
- if (node->children == NULL)
- return(0);
- else {
- xmlNodePtr child = node->children;
- xsltCompilerNodePush(cctxt, node);
- /*
- * Update the in-scope namespaces if needed.
- */
- if (node->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- /*
- * Parse all xsl:fallback children.
- */
- do {
- if ((child->type == XML_ELEMENT_NODE) &&
- IS_XSLT_ELEM_FAST(child) &&
- IS_XSLT_NAME(child, "fallback"))
- {
- cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
- xsltParseAnyXSLTElem(cctxt, child);
- }
- child = child->next;
- } while (child != NULL);
- xsltCompilerNodePop(cctxt, node);
- }
- return(0);
- }
- /**
- * xsltParseSequenceConstructor:
- *
- * @cctxt: the compilation context
- * @cur: the start-node of the content to be parsed
- *
- * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
- * This will additionally remove xsl:text elements from the tree.
- */
- void
- xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
- {
- xsltStyleType type;
- xmlNodePtr deleteNode = NULL;
- if (cctxt == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltParseSequenceConstructor: Bad arguments\n");
- cctxt->style->errors++;
- return;
- }
- /*
- * Detection of handled content of extension instructions.
- */
- if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- cctxt->inode->extContentHandled = 1;
- }
- if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
- return;
- /*
- * This is the content reffered to as a "template".
- * E.g. an xsl:element has such content model:
- * <xsl:element
- * name = { qname }
- * namespace = { uri-reference }
- * use-attribute-sets = qnames>
- * <!-- Content: template -->
- *
- * NOTE that in XSLT-2 the term "template" was abandoned due to
- * confusion with xsl:template and the term "sequence constructor"
- * was introduced instead.
- *
- * The following XSLT-instructions are allowed to appear:
- * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
- * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
- * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
- * xsl:message, xsl:fallback,
- * xsl:processing-instruction, xsl:comment, xsl:element
- * xsl:attribute.
- * Additional allowed content:
- * 1) extension instructions
- * 2) literal result elements
- * 3) PCDATA
- *
- * NOTE that this content model does *not* allow xsl:param.
- */
- while (cur != NULL) {
- if (deleteNode != NULL) {
- #ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseSequenceConstructor: removing xsl:text element\n");
- #endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- if (cur->type == XML_ELEMENT_NODE) {
- if (cur->psvi == xsltXSLTTextMarker) {
- /*
- * xsl:text elements
- * --------------------------------------------------------
- */
- xmlNodePtr tmp;
- cur->psvi = NULL;
- /*
- * Mark the xsl:text element for later deletion.
- */
- deleteNode = cur;
- /*
- * Validate content.
- */
- tmp = cur->children;
- if (tmp) {
- /*
- * We don't expect more than one text-node in the
- * content, since we already merged adjacent
- * text/CDATA-nodes and eliminated PI/comment-nodes.
- */
- if ((tmp->type == XML_TEXT_NODE) ||
- (tmp->next == NULL))
- {
- /*
- * Leave the contained text-node in the tree.
- */
- xmlUnlinkNode(tmp);
- xmlAddPrevSibling(cur, tmp);
- } else {
- tmp = NULL;
- xsltTransformError(NULL, cctxt->style, cur,
- "Element 'xsl:text': Invalid type "
- "of node found in content.\n");
- cctxt->style->errors++;
- }
- }
- if (cur->properties) {
- xmlAttrPtr attr;
- /*
- * TODO: We need to report errors for
- * invalid attrs.
- */
- attr = cur->properties;
- do {
- if ((attr->ns == NULL) &&
- (attr->name != NULL) &&
- (attr->name[0] == 'd') &&
- xmlStrEqual(attr->name,
- BAD_CAST "disable-output-escaping"))
- {
- /*
- * Attr "disable-output-escaping".
- * XSLT-2: This attribute is deprecated.
- */
- if ((attr->children != NULL) &&
- xmlStrEqual(attr->children->content,
- BAD_CAST "yes"))
- {
- /*
- * Disable output escaping for this
- * text node.
- */
- if (tmp)
- tmp->name = xmlStringTextNoenc;
- } else if ((attr->children == NULL) ||
- (attr->children->content == NULL) ||
- (!xmlStrEqual(attr->children->content,
- BAD_CAST "no")))
- {
- xsltTransformError(NULL, cctxt->style,
- cur,
- "Attribute 'disable-output-escaping': "
- "Invalid value. Expected is "
- "'yes' or 'no'.\n");
- cctxt->style->errors++;
- }
- break;
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- } else if (IS_XSLT_ELEM_FAST(cur)) {
- /*
- * TODO: Using the XSLT-marker is still not stable yet.
- */
- /* if (cur->psvi == xsltXSLTElemMarker) { */
- /*
- * XSLT instructions
- * --------------------------------------------------------
- */
- cur->psvi = NULL;
- type = xsltGetXSLTElementTypeByNode(cctxt, cur);
- switch (type) {
- case XSLT_FUNC_APPLYIMPORTS:
- case XSLT_FUNC_APPLYTEMPLATES:
- case XSLT_FUNC_ATTRIBUTE:
- case XSLT_FUNC_CALLTEMPLATE:
- case XSLT_FUNC_CHOOSE:
- case XSLT_FUNC_COMMENT:
- case XSLT_FUNC_COPY:
- case XSLT_FUNC_COPYOF:
- case XSLT_FUNC_DOCUMENT: /* Extra one */
- case XSLT_FUNC_ELEMENT:
- case XSLT_FUNC_FALLBACK:
- case XSLT_FUNC_FOREACH:
- case XSLT_FUNC_IF:
- case XSLT_FUNC_MESSAGE:
- case XSLT_FUNC_NUMBER:
- case XSLT_FUNC_PI:
- case XSLT_FUNC_TEXT:
- case XSLT_FUNC_VALUEOF:
- case XSLT_FUNC_VARIABLE:
- /*
- * Parse the XSLT element.
- */
- cctxt->inode->curChildType = type;
- xsltParseAnyXSLTElem(cctxt, cur);
- break;
- default:
- xsltParseUnknownXSLTElem(cctxt, cur);
- cur = cur->next;
- continue;
- }
- } else {
- /*
- * Non-XSLT elements
- * -----------------
- */
- xsltCompilerNodePush(cctxt, cur);
- /*
- * Update the in-scope namespaces if needed.
- */
- if (cur->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, cur);
- /*
- * The current element is either a literal result element
- * or an extension instruction.
- *
- * Process attr "xsl:extension-element-prefixes".
- * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
- * processed by the implementor of the extension function;
- * i.e., it won't be handled by the XSLT processor.
- */
- /* SPEC 1.0:
- * "exclude-result-prefixes" is only allowed on literal
- * result elements and "xsl:exclude-result-prefixes"
- * on xsl:stylesheet/xsl:transform.
- * SPEC 2.0:
- * "There are a number of standard attributes
- * that may appear on any XSLT element: specifically
- * version, exclude-result-prefixes,
- * extension-element-prefixes, xpath-default-namespace,
- * default-collation, and use-when."
- *
- * SPEC 2.0:
- * For literal result elements:
- * "xsl:version, xsl:exclude-result-prefixes,
- * xsl:extension-element-prefixes,
- * xsl:xpath-default-namespace,
- * xsl:default-collation, or xsl:use-when."
- */
- if (cur->properties)
- cctxt->inode->extElemNs =
- xsltParseExtElemPrefixes(cctxt,
- cur, cctxt->inode->extElemNs,
- XSLT_ELEMENT_CATEGORY_LRE);
- /*
- * Eval if we have an extension instruction here.
- */
- if ((cur->ns != NULL) &&
- (cctxt->inode->extElemNs != NULL) &&
- (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
- {
- /*
- * Extension instructions
- * ----------------------------------------------------
- * Mark the node information.
- */
- cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
- cctxt->inode->extContentHandled = 0;
- if (cur->psvi != NULL) {
- cur->psvi = NULL;
- /*
- * TODO: Temporary sanity check.
- */
- xsltTransformError(NULL, cctxt->style, cur,
- "Internal error in xsltParseSequenceConstructor(): "
- "Occupied PSVI field.\n");
- cctxt->style->errors++;
- cur = cur->next;
- continue;
- }
- cur->psvi = (void *)
- xsltPreComputeExtModuleElement(cctxt->style, cur);
- if (cur->psvi == NULL) {
- /*
- * OLD COMMENT: "Unknown element, maybe registered
- * at the context level. Mark it for later
- * recognition."
- * QUESTION: What does the xsltExtMarker mean?
- * ANSWER: It is used in
- * xsltApplySequenceConstructor() at
- * transformation-time to look out for extension
- * registered in the transformation context.
- */
- cur->psvi = (void *) xsltExtMarker;
- }
- /*
- * BIG NOTE: Now the ugly part. In previous versions
- * of Libxslt (until 1.1.16), all the content of an
- * extension instruction was processed and compiled without
- * the need of the extension-author to explicitely call
- * such a processing;.We now need to mimic this old
- * behaviour in order to avoid breaking old code
- * on the extension-author's side.
- * The mechanism:
- * 1) If the author does *not* set the
- * compile-time-flag @extContentHandled, then we'll
- * parse the content assuming that it's a "template"
- * (or "sequence constructor in XSLT 2.0 terms).
- * NOTE: If the extension is registered at
- * transformation-time only, then there's no way of
- * knowing that content shall be valid, and we'll
- * process the content the same way.
- * 2) If the author *does* set the flag, then we'll assume
- * that the author has handled the parsing him/herself
- * (e.g. called xsltParseSequenceConstructor(), etc.
- * explicitely in his/her code).
- */
- if ((cur->children != NULL) &&
- (cctxt->inode->extContentHandled == 0))
- {
- /*
- * Default parsing of the content using the
- * sequence-constructor model.
- */
- xsltParseSequenceConstructor(cctxt, cur->children);
- }
- } else {
- /*
- * Literal result element
- * ----------------------------------------------------
- * Allowed XSLT attributes:
- * xsl:extension-element-prefixes CDATA #IMPLIED
- * xsl:exclude-result-prefixes CDATA #IMPLIED
- * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
- * xsl:version NMTOKEN #IMPLIED
- */
- cur->psvi = NULL;
- cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
- if (cur->properties != NULL) {
- xmlAttrPtr attr = cur->properties;
- /*
- * Attribute "xsl:exclude-result-prefixes".
- */
- cctxt->inode->exclResultNs =
- xsltParseExclResultPrefixes(cctxt, cur,
- cctxt->inode->exclResultNs,
- XSLT_ELEMENT_CATEGORY_LRE);
- /*
- * Attribute "xsl:version".
- */
- xsltParseAttrXSLTVersion(cctxt, cur,
- XSLT_ELEMENT_CATEGORY_LRE);
- /*
- * Report invalid XSLT attributes.
- * For XSLT 1.0 only xsl:use-attribute-sets is allowed
- * next to xsl:version, xsl:exclude-result-prefixes and
- * xsl:extension-element-prefixes.
- *
- * Mark all XSLT attributes, in order to skip such
- * attributes when instantiating the LRE.
- */
- do {
- if ((attr->psvi != xsltXSLTAttrMarker) &&
- IS_XSLT_ATTR_FAST(attr))
- {
- if (! xmlStrEqual(attr->name,
- BAD_CAST "use-attribute-sets"))
- {
- xsltTransformError(NULL, cctxt->style,
- cur,
- "Unknown XSLT attribute '%s'.\n",
- attr->name);
- cctxt->style->errors++;
- } else {
- /*
- * XSLT attr marker.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- /*
- * Create/reuse info for the literal result element.
- */
- if (cctxt->inode->nsChanged)
- xsltLREInfoCreate(cctxt, cur, 1);
- cur->psvi = cctxt->inode->litResElemInfo;
- /*
- * Apply ns-aliasing on the element and on its attributes.
- */
- if (cctxt->hasNsAliases)
- xsltLREBuildEffectiveNs(cctxt, cur);
- /*
- * Compile attribute value templates (AVT).
- */
- if (cur->properties) {
- xmlAttrPtr attr = cur->properties;
- while (attr != NULL) {
- xsltCompileAttr(cctxt->style, attr);
- attr = attr->next;
- }
- }
- /*
- * Parse the content, which is defined to be a "template"
- * (or "sequence constructor" in XSLT 2.0 terms).
- */
- if (cur->children != NULL) {
- xsltParseSequenceConstructor(cctxt, cur->children);
- }
- }
- /*
- * Leave the non-XSLT element.
- */
- xsltCompilerNodePop(cctxt, cur);
- }
- }
- cur = cur->next;
- }
- if (deleteNode != NULL) {
- #ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseSequenceConstructor: removing xsl:text element\n");
- #endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- }
- /**
- * xsltParseTemplateContent:
- * @style: the XSLT stylesheet
- * @templ: the node containing the content to be parsed
- *
- * Parses and compiles the content-model of an xsl:template element.
- * Note that this is *not* the "template" content model (or "sequence
- * constructor" in XSLT 2.0); it it allows addional xsl:param
- * elements as immediate children of @templ.
- *
- * Called by:
- * exsltFuncFunctionComp() (EXSLT, functions.c)
- * So this is intended to be called from extension functions.
- */
- void
- xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
- if ((style == NULL) || (templ == NULL) ||
- (templ->type == XML_NAMESPACE_DECL))
- return;
- /*
- * Detection of handled content of extension instructions.
- */
- if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- XSLT_CCTXT(style)->inode->extContentHandled = 1;
- }
- if (templ->children != NULL) {
- xmlNodePtr child = templ->children;
- /*
- * Process xsl:param elements, which can only occur as the
- * immediate children of xsl:template (well, and of any
- * user-defined extension instruction if needed).
- */
- do {
- if ((child->type == XML_ELEMENT_NODE) &&
- IS_XSLT_ELEM_FAST(child) &&
- IS_XSLT_NAME(child, "param"))
- {
- XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
- xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
- } else
- break;
- child = child->next;
- } while (child != NULL);
- /*
- * Parse the content and register the pattern.
- */
- xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
- }
- }
- #else /* XSLT_REFACTORED */
- /**
- * xsltParseTemplateContent:
- * @style: the XSLT stylesheet
- * @templ: the container node (can be a document for literal results)
- *
- * parse a template content-model
- * Clean-up the template content from unwanted ignorable blank nodes
- * and process xslt:text
- */
- void
- xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
- xmlNodePtr cur, delete;
- if ((style == NULL) || (templ == NULL) ||
- (templ->type == XML_NAMESPACE_DECL)) return;
- /*
- * This content comes from the stylesheet
- * For stylesheets, the set of whitespace-preserving
- * element names consists of just xsl:text.
- */
- cur = templ->children;
- delete = NULL;
- while (cur != NULL) {
- if (delete != NULL) {
- #ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseTemplateContent: removing text\n");
- #endif
- xmlUnlinkNode(delete);
- xmlFreeNode(delete);
- delete = NULL;
- }
- if (IS_XSLT_ELEM(cur)) {
- xsltStylePreCompute(style, cur);
- if (IS_XSLT_NAME(cur, "text")) {
- /*
- * TODO: Processing of xsl:text should be moved to
- * xsltPreprocessStylesheet(), since otherwise this
- * will be performed for every multiply included
- * stylesheet; i.e. this here is not skipped with
- * the use of the style->nopreproc flag.
- */
- if (cur->children != NULL) {
- xmlChar *prop;
- xmlNodePtr text = cur->children, next;
- int noesc = 0;
- prop = xmlGetNsProp(cur,
- (const xmlChar *)"disable-output-escaping",
- NULL);
- if (prop != NULL) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Disable escaping: %s\n", text->content);
- #endif
- if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
- noesc = 1;
- } else if (!xmlStrEqual(prop,
- (const xmlChar *)"no")){
- xsltTransformError(NULL, style, cur,
- "xsl:text: disable-output-escaping allows only yes or no\n");
- style->warnings++;
- }
- xmlFree(prop);
- }
- while (text != NULL) {
- if (text->type == XML_COMMENT_NODE) {
- text = text->next;
- continue;
- }
- if ((text->type != XML_TEXT_NODE) &&
- (text->type != XML_CDATA_SECTION_NODE)) {
- xsltTransformError(NULL, style, cur,
- "xsltParseTemplateContent: xslt:text content problem\n");
- style->errors++;
- break;
- }
- if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
- text->name = xmlStringTextNoenc;
- text = text->next;
- }
- /*
- * replace xsl:text by the list of childs
- */
- if (text == NULL) {
- text = cur->children;
- while (text != NULL) {
- if ((style->internalized) &&
- (text->content != NULL) &&
- (!xmlDictOwns(style->dict, text->content))) {
- /*
- * internalize the text string
- */
- if (text->doc->dict != NULL) {
- const xmlChar *tmp;
- tmp = xmlDictLookup(text->doc->dict,
- text->content, -1);
- if (tmp != text->content) {
- xmlNodeSetContent(text, NULL);
- text->content = (xmlChar *) tmp;
- }
- }
- }
- next = text->next;
- xmlUnlinkNode(text);
- xmlAddPrevSibling(cur, text);
- text = next;
- }
- }
- }
- delete = cur;
- goto skip_children;
- }
- }
- else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
- (xsltCheckExtPrefix(style, cur->ns->prefix)))
- {
- /*
- * okay this is an extension element compile it too
- */
- xsltStylePreCompute(style, cur);
- }
- else if (cur->type == XML_ELEMENT_NODE)
- {
- /*
- * This is an element which will be output as part of the
- * template exectution, precompile AVT if found.
- */
- if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
- cur->ns = xmlSearchNsByHref(cur->doc, cur,
- style->defaultAlias);
- }
- if (cur->properties != NULL) {
- xmlAttrPtr attr = cur->properties;
- while (attr != NULL) {
- xsltCompileAttr(style, attr);
- attr = attr->next;
- }
- }
- }
- /*
- * Skip to next node
- */
- if (cur->children != NULL) {
- if (cur->children->type != XML_ENTITY_DECL) {
- cur = cur->children;
- continue;
- }
- }
- skip_children:
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
- do {
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == templ) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- if (delete != NULL) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseTemplateContent: removing text\n");
- #endif
- xmlUnlinkNode(delete);
- xmlFreeNode(delete);
- delete = NULL;
- }
- /*
- * Skip the first params
- */
- cur = templ->children;
- while (cur != NULL) {
- if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
- break;
- cur = cur->next;
- }
- /*
- * Browse the remainder of the template
- */
- while (cur != NULL) {
- if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
- xmlNodePtr param = cur;
- xsltTransformError(NULL, style, cur,
- "xsltParseTemplateContent: ignoring misplaced param element\n");
- if (style != NULL) style->warnings++;
- cur = cur->next;
- xmlUnlinkNode(param);
- xmlFreeNode(param);
- } else
- break;
- }
- }
- #endif /* else XSLT_REFACTORED */
- /**
- * xsltParseStylesheetKey:
- * @style: the XSLT stylesheet
- * @key: the "key" element
- *
- * <!-- Category: top-level-element -->
- * <xsl:key name = qname, match = pattern, use = expression />
- *
- * parse an XSLT stylesheet key definition and register it
- */
- static void
- xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
- xmlChar *prop = NULL;
- xmlChar *use = NULL;
- xmlChar *match = NULL;
- xmlChar *name = NULL;
- xmlChar *nameURI = NULL;
- if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
- return;
- /*
- * Get arguments
- */
- prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
- if (prop != NULL) {
- const xmlChar *URI;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(key, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- } else {
- name = prop;
- if (URI != NULL)
- nameURI = xmlStrdup(URI);
- }
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetKey: name %s\n", name);
- #endif
- } else {
- xsltTransformError(NULL, style, key,
- "xsl:key : error missing name\n");
- if (style != NULL) style->errors++;
- goto error;
- }
- match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
- if (match == NULL) {
- xsltTransformError(NULL, style, key,
- "xsl:key : error missing match\n");
- if (style != NULL) style->errors++;
- goto error;
- }
- use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
- if (use == NULL) {
- xsltTransformError(NULL, style, key,
- "xsl:key : error missing use\n");
- if (style != NULL) style->errors++;
- goto error;
- }
- /*
- * register the keys
- */
- xsltAddKey(style, name, nameURI, match, use, key);
- error:
- if (use != NULL)
- xmlFree(use);
- if (match != NULL)
- xmlFree(match);
- if (name != NULL)
- xmlFree(name);
- if (nameURI != NULL)
- xmlFree(nameURI);
- if (key->children != NULL) {
- xsltParseContentError(style, key->children);
- }
- }
- #ifdef XSLT_REFACTORED
- /**
- * xsltParseXSLTTemplate:
- * @style: the XSLT stylesheet
- * @template: the "template" element
- *
- * parse an XSLT stylesheet template building the associated structures
- * TODO: Is @style ever expected to be NULL?
- *
- * Called from:
- * xsltParseXSLTStylesheet()
- * xsltParseStylesheetTop()
- */
- static void
- xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
- xsltTemplatePtr templ;
- xmlChar *prop;
- double priority;
- if ((cctxt == NULL) || (templNode == NULL) ||
- (templNode->type != XML_ELEMENT_NODE))
- return;
- /*
- * Create and link the structure
- */
- templ = xsltNewTemplate();
- if (templ == NULL)
- return;
- xsltCompilerNodePush(cctxt, templNode);
- if (templNode->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, templNode);
- templ->next = cctxt->style->templates;
- cctxt->style->templates = templ;
- templ->style = cctxt->style;
- /*
- * Attribute "mode".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
- if (prop != NULL) {
- const xmlChar *modeURI;
- /*
- * TODO: We need a standardized function for extraction
- * of namespace names and local names from QNames.
- * Don't use xsltGetQNameURI() as it cannot channe�
- * reports through the context.
- */
- modeURI = xsltGetQNameURI(templNode, &prop);
- if (prop == NULL) {
- cctxt->style->errors++;
- goto error;
- }
- templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
- xmlFree(prop);
- prop = NULL;
- if (xmlValidateNCName(templ->mode, 0)) {
- xsltTransformError(NULL, cctxt->style, templNode,
- "xsl:template: Attribute 'mode': The local part '%s' "
- "of the value is not a valid NCName.\n", templ->name);
- cctxt->style->errors++;
- goto error;
- }
- if (modeURI != NULL)
- templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseXSLTTemplate: mode %s\n", templ->mode);
- #endif
- }
- /*
- * Attribute "match".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
- if (prop != NULL) {
- templ->match = prop;
- prop = NULL;
- }
- /*
- * Attribute "priority".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
- if (prop != NULL) {
- priority = xmlXPathStringEvalNumber(prop);
- templ->priority = (float) priority;
- xmlFree(prop);
- prop = NULL;
- }
- /*
- * Attribute "name".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
- if (prop != NULL) {
- const xmlChar *nameURI;
- xsltTemplatePtr curTempl;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- nameURI = xsltGetQNameURI(templNode, &prop);
- if (prop == NULL) {
- cctxt->style->errors++;
- goto error;
- }
- templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
- xmlFree(prop);
- prop = NULL;
- if (xmlValidateNCName(templ->name, 0)) {
- xsltTransformError(NULL, cctxt->style, templNode,
- "xsl:template: Attribute 'name': The local part '%s' of "
- "the value is not a valid NCName.\n", templ->name);
- cctxt->style->errors++;
- goto error;
- }
- if (nameURI != NULL)
- templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
- curTempl = templ->next;
- while (curTempl != NULL) {
- if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
- xmlStrEqual(curTempl->nameURI, nameURI) ) ||
- (nameURI == NULL && curTempl->nameURI == NULL &&
- xmlStrEqual(curTempl->name, templ->name)))
- {
- xsltTransformError(NULL, cctxt->style, templNode,
- "xsl:template: error duplicate name '%s'\n", templ->name);
- cctxt->style->errors++;
- goto error;
- }
- curTempl = curTempl->next;
- }
- }
- if (templNode->children != NULL) {
- xsltParseTemplateContent(cctxt->style, templNode);
- /*
- * MAYBE TODO: Custom behaviour: In order to stay compatible with
- * Xalan and MSXML(.NET), we could allow whitespace
- * to appear before an xml:param element; this whitespace
- * will additionally become part of the "template".
- * NOTE that this is totally deviates from the spec, but
- * is the de facto behaviour of Xalan and MSXML(.NET).
- * Personally I wouldn't allow this, since if we have:
- * <xsl:template ...xml:space="preserve">
- * <xsl:param name="foo"/>
- * <xsl:param name="bar"/>
- * <xsl:param name="zoo"/>
- * ... the whitespace between every xsl:param would be
- * added to the result tree.
- */
- }
- templ->elem = templNode;
- templ->content = templNode->children;
- xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
- error:
- xsltCompilerNodePop(cctxt, templNode);
- return;
- }
- #else /* XSLT_REFACTORED */
- /**
- * xsltParseStylesheetTemplate:
- * @style: the XSLT stylesheet
- * @template: the "template" element
- *
- * parse an XSLT stylesheet template building the associated structures
- */
- static void
- xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
- xsltTemplatePtr ret;
- xmlChar *prop;
- xmlChar *mode = NULL;
- xmlChar *modeURI = NULL;
- double priority;
- if ((style == NULL) || (template == NULL) ||
- (template->type != XML_ELEMENT_NODE))
- return;
- /*
- * Create and link the structure
- */
- ret = xsltNewTemplate();
- if (ret == NULL)
- return;
- ret->next = style->templates;
- style->templates = ret;
- ret->style = style;
- /*
- * Get inherited namespaces
- */
- /*
- * TODO: Apply the optimized in-scope-namespace mechanism
- * as for the other XSLT instructions.
- */
- xsltGetInheritedNsList(style, ret, template);
- /*
- * Get arguments
- */
- prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
- if (prop != NULL) {
- const xmlChar *URI;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(template, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- } else {
- mode = prop;
- if (URI != NULL)
- modeURI = xmlStrdup(URI);
- }
- ret->mode = xmlDictLookup(style->dict, mode, -1);
- ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetTemplate: mode %s\n", mode);
- #endif
- if (mode != NULL) xmlFree(mode);
- if (modeURI != NULL) xmlFree(modeURI);
- }
- prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
- if (prop != NULL) {
- if (ret->match != NULL) xmlFree(ret->match);
- ret->match = prop;
- }
- prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
- if (prop != NULL) {
- priority = xmlXPathStringEvalNumber(prop);
- ret->priority = (float) priority;
- xmlFree(prop);
- }
- prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
- if (prop != NULL) {
- const xmlChar *URI;
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(template, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- } else {
- if (xmlValidateNCName(prop,0)) {
- xsltTransformError(NULL, style, template,
- "xsl:template : error invalid name '%s'\n", prop);
- if (style != NULL) style->errors++;
- xmlFree(prop);
- goto error;
- }
- ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
- xmlFree(prop);
- prop = NULL;
- if (URI != NULL)
- ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
- else
- ret->nameURI = NULL;
- }
- }
- /*
- * parse the content and register the pattern
- */
- xsltParseTemplateContent(style, template);
- ret->elem = template;
- ret->content = template->children;
- xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
- error:
- return;
- }
- #endif /* else XSLT_REFACTORED */
- #ifdef XSLT_REFACTORED
- /**
- * xsltIncludeComp:
- * @cctxt: the compilation context
- * @node: the xsl:include node
- *
- * Process the xslt include node on the source node
- */
- static xsltStyleItemIncludePtr
- xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
- xsltStyleItemIncludePtr item;
- if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
- return(NULL);
- node->psvi = NULL;
- item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
- if (item == NULL) {
- xsltTransformError(NULL, cctxt->style, node,
- "xsltIncludeComp : malloc failed\n");
- cctxt->style->errors++;
- return(NULL);
- }
- memset(item, 0, sizeof(xsltStyleItemInclude));
- node->psvi = item;
- item->inst = node;
- item->type = XSLT_FUNC_INCLUDE;
- item->next = cctxt->style->preComps;
- cctxt->style->preComps = (xsltElemPreCompPtr) item;
- return(item);
- }
- /**
- * xsltParseFindTopLevelElem:
- */
- static int
- xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr cur,
- const xmlChar *name,
- const xmlChar *namespaceURI,
- int breakOnOtherElem,
- xmlNodePtr *resultNode)
- {
- if (name == NULL)
- return(-1);
- *resultNode = NULL;
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE) {
- if ((cur->ns != NULL) && (cur->name != NULL)) {
- if ((*(cur->name) == *name) &&
- xmlStrEqual(cur->name, name) &&
- xmlStrEqual(cur->ns->href, namespaceURI))
- {
- *resultNode = cur;
- return(1);
- }
- }
- if (breakOnOtherElem)
- break;
- }
- cur = cur->next;
- }
- *resultNode = cur;
- return(0);
- }
- static int
- xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node,
- xsltStyleType type)
- {
- int ret = 0;
- /*
- * TODO: The reason why this function exists:
- * due to historical reasons some of the
- * top-level declarations are processed by functions
- * in other files. Since we need still to set
- * up the node-info and generate information like
- * in-scope namespaces, this is a wrapper around
- * those old parsing functions.
- */
- xsltCompilerNodePush(cctxt, node);
- if (node->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- cctxt->inode->type = type;
- switch (type) {
- case XSLT_FUNC_INCLUDE:
- {
- int oldIsInclude;
- if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
- goto exit;
- /*
- * Mark this stylesheet tree as being currently included.
- */
- oldIsInclude = cctxt->isInclude;
- cctxt->isInclude = 1;
- if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
- cctxt->style->errors++;
- }
- cctxt->isInclude = oldIsInclude;
- }
- break;
- case XSLT_FUNC_PARAM:
- xsltStylePreCompute(cctxt->style, node);
- xsltParseGlobalParam(cctxt->style, node);
- break;
- case XSLT_FUNC_VARIABLE:
- xsltStylePreCompute(cctxt->style, node);
- xsltParseGlobalVariable(cctxt->style, node);
- break;
- case XSLT_FUNC_ATTRSET:
- xsltParseStylesheetAttributeSet(cctxt->style, node);
- break;
- default:
- xsltTransformError(NULL, cctxt->style, node,
- "Internal error: (xsltParseTopLevelXSLTElem) "
- "Cannot handle this top-level declaration.\n");
- cctxt->style->errors++;
- ret = -1;
- }
- exit:
- xsltCompilerNodePop(cctxt, node);
- return(ret);
- }
- #if 0
- static int
- xsltParseRemoveWhitespace(xmlNodePtr node)
- {
- if ((node == NULL) || (node->children == NULL))
- return(0);
- else {
- xmlNodePtr delNode = NULL, child = node->children;
- do {
- if (delNode) {
- xmlUnlinkNode(delNode);
- xmlFreeNode(delNode);
- delNode = NULL;
- }
- if (((child->type == XML_TEXT_NODE) ||
- (child->type == XML_CDATA_SECTION_NODE)) &&
- (IS_BLANK_NODE(child)))
- delNode = child;
- child = child->next;
- } while (child != NULL);
- if (delNode) {
- xmlUnlinkNode(delNode);
- xmlFreeNode(delNode);
- delNode = NULL;
- }
- }
- return(0);
- }
- #endif
- static int
- xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
- {
- #ifdef WITH_XSLT_DEBUG_PARSING
- int templates = 0;
- #endif
- xmlNodePtr cur, start = NULL;
- xsltStylesheetPtr style;
- if ((cctxt == NULL) || (node == NULL) ||
- (node->type != XML_ELEMENT_NODE))
- return(-1);
- style = cctxt->style;
- /*
- * At this stage all import declarations of all stylesheet modules
- * with the same stylesheet level have been processed.
- * Now we can safely parse the rest of the declarations.
- */
- if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
- {
- xsltDocumentPtr include;
- /*
- * URGENT TODO: Make this work with simplified stylesheets!
- * I.e., when we won't find an xsl:stylesheet element.
- */
- /*
- * This is as include declaration.
- */
- include = ((xsltStyleItemIncludePtr) node->psvi)->include;
- if (include == NULL) {
- /* TODO: raise error? */
- return(-1);
- }
- /*
- * TODO: Actually an xsl:include should locate an embedded
- * stylesheet as well; so the document-element won't always
- * be the element where the actual stylesheet is rooted at.
- * But such embedded stylesheets are not supported by Libxslt yet.
- */
- node = xmlDocGetRootElement(include->doc);
- if (node == NULL) {
- return(-1);
- }
- }
- if (node->children == NULL)
- return(0);
- /*
- * Push the xsl:stylesheet/xsl:transform element.
- */
- xsltCompilerNodePush(cctxt, node);
- cctxt->inode->isRoot = 1;
- cctxt->inode->nsChanged = 0;
- /*
- * Start with the naked dummy info for literal result elements.
- */
- cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
- /*
- * In every case, we need to have
- * the in-scope namespaces of the element, where the
- * stylesheet is rooted at, regardless if it's an XSLT
- * instruction or a literal result instruction (or if
- * this is an embedded stylesheet).
- */
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- /*
- * Process attributes of xsl:stylesheet/xsl:transform.
- * --------------------------------------------------
- * Allowed are:
- * id = id
- * extension-element-prefixes = tokens
- * exclude-result-prefixes = tokens
- * version = number (mandatory)
- */
- if (xsltParseAttrXSLTVersion(cctxt, node,
- XSLT_ELEMENT_CATEGORY_XSLT) == 0)
- {
- /*
- * Attribute "version".
- * XSLT 1.0: "An xsl:stylesheet element *must* have a version
- * attribute, indicating the version of XSLT that the
- * stylesheet requires".
- * The root element of a simplified stylesheet must also have
- * this attribute.
- */
- #ifdef XSLT_REFACTORED_MANDATORY_VERSION
- if (isXsltElem)
- xsltTransformError(NULL, cctxt->style, node,
- "The attribute 'version' is missing.\n");
- cctxt->style->errors++;
- #else
- /* OLD behaviour. */
- xsltTransformError(NULL, cctxt->style, node,
- "xsl:version is missing: document may not be a stylesheet\n");
- cctxt->style->warnings++;
- #endif
- }
- /*
- * The namespaces declared by the attributes
- * "extension-element-prefixes" and
- * "exclude-result-prefixes" are local to *this*
- * stylesheet tree; i.e., they are *not* visible to
- * other stylesheet-modules, whether imported or included.
- *
- * Attribute "extension-element-prefixes".
- */
- cctxt->inode->extElemNs =
- xsltParseExtElemPrefixes(cctxt, node, NULL,
- XSLT_ELEMENT_CATEGORY_XSLT);
- /*
- * Attribute "exclude-result-prefixes".
- */
- cctxt->inode->exclResultNs =
- xsltParseExclResultPrefixes(cctxt, node, NULL,
- XSLT_ELEMENT_CATEGORY_XSLT);
- /*
- * Create/reuse info for the literal result element.
- */
- if (cctxt->inode->nsChanged)
- xsltLREInfoCreate(cctxt, node, 0);
- /*
- * Processed top-level elements:
- * ----------------------------
- * xsl:variable, xsl:param (QName, in-scope ns,
- * expression (vars allowed))
- * xsl:attribute-set (QName, in-scope ns)
- * xsl:strip-space, xsl:preserve-space (XPath NameTests,
- * in-scope ns)
- * I *think* global scope, merge with includes
- * xsl:output (QName, in-scope ns)
- * xsl:key (QName, in-scope ns, pattern,
- * expression (vars *not* allowed))
- * xsl:decimal-format (QName, needs in-scope ns)
- * xsl:namespace-alias (in-scope ns)
- * global scope, merge with includes
- * xsl:template (last, QName, pattern)
- *
- * (whitespace-only text-nodes have *not* been removed
- * yet; this will be done in xsltParseSequenceConstructor)
- *
- * Report misplaced child-nodes first.
- */
- cur = node->children;
- while (cur != NULL) {
- if (cur->type == XML_TEXT_NODE) {
- xsltTransformError(NULL, style, cur,
- "Misplaced text node (content: '%s').\n",
- (cur->content != NULL) ? cur->content : BAD_CAST "");
- style->errors++;
- } else if (cur->type != XML_ELEMENT_NODE) {
- xsltTransformError(NULL, style, cur, "Misplaced node.\n");
- style->errors++;
- }
- cur = cur->next;
- }
- /*
- * Skip xsl:import elements; they have been processed
- * already.
- */
- cur = node->children;
- while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
- cur = cur->next;
- if (cur == NULL)
- goto exit;
- start = cur;
- /*
- * Process all top-level xsl:param elements.
- */
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
- cur = cur->next;
- }
- /*
- * Process all top-level xsl:variable elements.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
- cur = cur->next;
- }
- /*
- * Process all the rest of top-level elements.
- */
- cur = start;
- while (cur != NULL) {
- /*
- * Process element nodes.
- */
- if (cur->type == XML_ELEMENT_NODE) {
- if (cur->ns == NULL) {
- xsltTransformError(NULL, style, cur,
- "Unexpected top-level element in no namespace.\n");
- style->errors++;
- cur = cur->next;
- continue;
- }
- /*
- * Process all XSLT elements.
- */
- if (IS_XSLT_ELEM_FAST(cur)) {
- /*
- * xsl:import is only allowed at the beginning.
- */
- if (IS_XSLT_NAME(cur, "import")) {
- xsltTransformError(NULL, style, cur,
- "Misplaced xsl:import element.\n");
- style->errors++;
- cur = cur->next;
- continue;
- }
- /*
- * TODO: Change the return type of the parsing functions
- * to int.
- */
- if (IS_XSLT_NAME(cur, "template")) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- templates++;
- #endif
- /*
- * TODO: Is the position of xsl:template in the
- * tree significant? If not it would be easier to
- * parse them at a later stage.
- */
- xsltParseXSLTTemplate(cctxt, cur);
- } else if (IS_XSLT_NAME(cur, "variable")) {
- /* NOP; done already */
- } else if (IS_XSLT_NAME(cur, "param")) {
- /* NOP; done already */
- } else if (IS_XSLT_NAME(cur, "include")) {
- if (cur->psvi != NULL)
- xsltParseXSLTStylesheetElemCore(cctxt, cur);
- else {
- xsltTransformError(NULL, style, cur,
- "Internal error: "
- "(xsltParseXSLTStylesheetElemCore) "
- "The xsl:include element was not compiled.\n");
- style->errors++;
- }
- } else if (IS_XSLT_NAME(cur, "strip-space")) {
- /* No node info needed. */
- xsltParseStylesheetStripSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "preserve-space")) {
- /* No node info needed. */
- xsltParseStylesheetPreserveSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "output")) {
- /* No node-info needed. */
- xsltParseStylesheetOutput(style, cur);
- } else if (IS_XSLT_NAME(cur, "key")) {
- /* TODO: node-info needed for expressions ? */
- xsltParseStylesheetKey(style, cur);
- } else if (IS_XSLT_NAME(cur, "decimal-format")) {
- /* No node-info needed. */
- xsltParseStylesheetDecimalFormat(style, cur);
- } else if (IS_XSLT_NAME(cur, "attribute-set")) {
- xsltParseTopLevelXSLTElem(cctxt, cur,
- XSLT_FUNC_ATTRSET);
- } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
- /* NOP; done already */
- } else {
- if (cctxt->inode->forwardsCompat) {
- /*
- * Forwards-compatible mode:
- *
- * XSLT-1: "if it is a top-level element and
- * XSLT 1.0 does not allow such elements as top-level
- * elements, then the element must be ignored along
- * with its content;"
- */
- /*
- * TODO: I don't think we should generate a warning.
- */
- xsltTransformError(NULL, style, cur,
- "Forwards-compatible mode: Ignoring unknown XSLT "
- "element '%s'.\n", cur->name);
- style->warnings++;
- } else {
- xsltTransformError(NULL, style, cur,
- "Unknown XSLT element '%s'.\n", cur->name);
- style->errors++;
- }
- }
- } else {
- xsltTopLevelFunction function;
- /*
- * Process non-XSLT elements, which are in a
- * non-NULL namespace.
- */
- /*
- * QUESTION: What does xsltExtModuleTopLevelLookup()
- * do exactly?
- */
- function = xsltExtModuleTopLevelLookup(cur->name,
- cur->ns->href);
- if (function != NULL)
- function(style, cur);
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseXSLTStylesheetElemCore : User-defined "
- "data element '%s'.\n", cur->name);
- #endif
- }
- }
- cur = cur->next;
- }
- exit:
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "### END of parsing top-level elements of doc '%s'.\n",
- node->doc->URL);
- xsltGenericDebug(xsltGenericDebugContext,
- "### Templates: %d\n", templates);
- #ifdef XSLT_REFACTORED
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max inodes: %d\n", cctxt->maxNodeInfos);
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max LREs : %d\n", cctxt->maxLREs);
- #endif /* XSLT_REFACTORED */
- #endif /* WITH_XSLT_DEBUG_PARSING */
- xsltCompilerNodePop(cctxt, node);
- return(0);
- }
- /**
- * xsltParseXSLTStylesheet:
- * @cctxt: the compiler context
- * @node: the xsl:stylesheet/xsl:transform element-node
- *
- * Parses the xsl:stylesheet and xsl:transform element.
- *
- * <xsl:stylesheet
- * id = id
- * extension-element-prefixes = tokens
- * exclude-result-prefixes = tokens
- * version = number>
- * <!-- Content: (xsl:import*, top-level-elements) -->
- * </xsl:stylesheet>
- *
- * BIG TODO: The xsl:include stuff.
- *
- * Called by xsltParseStylesheetTree()
- *
- * Returns 0 on success, a positive result on errors and
- * -1 on API or internal errors.
- */
- static int
- xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
- {
- xmlNodePtr cur, start;
- if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
- return(-1);
- if (node->children == NULL)
- goto exit;
- /*
- * Process top-level elements:
- * xsl:import (must be first)
- * xsl:include (this is just a pre-processing)
- */
- cur = node->children;
- /*
- * Process xsl:import elements.
- * XSLT 1.0: "The xsl:import element children must precede all
- * other element children of an xsl:stylesheet element,
- * including any xsl:include element children."
- */
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
- {
- if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
- cctxt->style->errors++;
- }
- cur = cur->next;
- }
- if (cur == NULL)
- goto exit;
- start = cur;
- /*
- * Pre-process all xsl:include elements.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
- cur = cur->next;
- }
- /*
- * Pre-process all xsl:namespace-alias elements.
- * URGENT TODO: This won't work correctly: the order of included
- * aliases and aliases defined here is significant.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltNamespaceAlias(cctxt->style, cur);
- cur = cur->next;
- }
- if (cctxt->isInclude) {
- /*
- * If this stylesheet is intended for inclusion, then
- * we will process only imports and includes.
- */
- goto exit;
- }
- /*
- * Now parse the rest of the top-level elements.
- */
- xsltParseXSLTStylesheetElemCore(cctxt, node);
- exit:
- return(0);
- }
- #else /* XSLT_REFACTORED */
- /**
- * xsltParseStylesheetTop:
- * @style: the XSLT stylesheet
- * @top: the top level "stylesheet" or "transform" element
- *
- * scan the top level elements of an XSL stylesheet
- */
- static void
- xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
- xmlNodePtr cur;
- xmlChar *prop;
- #ifdef WITH_XSLT_DEBUG_PARSING
- int templates = 0;
- #endif
- if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
- return;
- prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
- if (prop == NULL) {
- xsltTransformError(NULL, style, top,
- "xsl:version is missing: document may not be a stylesheet\n");
- if (style != NULL) style->warnings++;
- } else {
- if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
- (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
- xsltTransformError(NULL, style, top,
- "xsl:version: only 1.1 features are supported\n");
- if (style != NULL) {
- style->forwards_compatible = 1;
- style->warnings++;
- }
- }
- xmlFree(prop);
- }
- /*
- * process xsl:import elements
- */
- cur = top->children;
- while (cur != NULL) {
- if (IS_BLANK_NODE(cur)) {
- cur = cur->next;
- continue;
- }
- if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
- if (xsltParseStylesheetImport(style, cur) != 0)
- if (style != NULL) style->errors++;
- } else
- break;
- cur = cur->next;
- }
- /*
- * process other top-level elements
- */
- while (cur != NULL) {
- if (IS_BLANK_NODE(cur)) {
- cur = cur->next;
- continue;
- }
- if (cur->type == XML_TEXT_NODE) {
- if (cur->content != NULL) {
- xsltTransformError(NULL, style, cur,
- "misplaced text node: '%s'\n", cur->content);
- }
- if (style != NULL) style->errors++;
- cur = cur->next;
- continue;
- }
- if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "Found a top-level element %s with null namespace URI\n",
- cur->name);
- if (style != NULL) style->errors++;
- cur = cur->next;
- continue;
- }
- if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
- xsltTopLevelFunction function;
- function = xsltExtModuleTopLevelLookup(cur->name,
- cur->ns->href);
- if (function != NULL)
- function(style, cur);
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetTop : found foreign element %s\n",
- cur->name);
- #endif
- cur = cur->next;
- continue;
- }
- if (IS_XSLT_NAME(cur, "import")) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetTop: ignoring misplaced import element\n");
- if (style != NULL) style->errors++;
- } else if (IS_XSLT_NAME(cur, "include")) {
- if (xsltParseStylesheetInclude(style, cur) != 0)
- if (style != NULL) style->errors++;
- } else if (IS_XSLT_NAME(cur, "strip-space")) {
- xsltParseStylesheetStripSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "preserve-space")) {
- xsltParseStylesheetPreserveSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "output")) {
- xsltParseStylesheetOutput(style, cur);
- } else if (IS_XSLT_NAME(cur, "key")) {
- xsltParseStylesheetKey(style, cur);
- } else if (IS_XSLT_NAME(cur, "decimal-format")) {
- xsltParseStylesheetDecimalFormat(style, cur);
- } else if (IS_XSLT_NAME(cur, "attribute-set")) {
- xsltParseStylesheetAttributeSet(style, cur);
- } else if (IS_XSLT_NAME(cur, "variable")) {
- xsltParseGlobalVariable(style, cur);
- } else if (IS_XSLT_NAME(cur, "param")) {
- xsltParseGlobalParam(style, cur);
- } else if (IS_XSLT_NAME(cur, "template")) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- templates++;
- #endif
- xsltParseStylesheetTemplate(style, cur);
- } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
- xsltNamespaceAlias(style, cur);
- } else {
- if ((style != NULL) && (style->forwards_compatible == 0)) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetTop: unknown %s element\n",
- cur->name);
- if (style != NULL) style->errors++;
- }
- }
- cur = cur->next;
- }
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "parsed %d templates\n", templates);
- #endif
- }
- #endif /* else of XSLT_REFACTORED */
- #ifdef XSLT_REFACTORED
- /**
- * xsltParseSimplifiedStylesheetTree:
- *
- * @style: the stylesheet (TODO: Change this to the compiler context)
- * @doc: the document containing the stylesheet.
- * @node: the node where the stylesheet is rooted at
- *
- * Returns 0 in case of success, a positive result if an error occurred
- * and -1 on API and internal errors.
- */
- static int
- xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
- xmlDocPtr doc,
- xmlNodePtr node)
- {
- xsltTemplatePtr templ;
- if ((cctxt == NULL) || (node == NULL))
- return(-1);
- if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
- {
- /*
- * TODO: Adjust report, since this might be an
- * embedded stylesheet.
- */
- xsltTransformError(NULL, cctxt->style, node,
- "The attribute 'xsl:version' is missing; cannot identify "
- "this document as an XSLT stylesheet document.\n");
- cctxt->style->errors++;
- return(1);
- }
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
- #endif
- /*
- * Create and link the template
- */
- templ = xsltNewTemplate();
- if (templ == NULL) {
- return(-1);
- }
- templ->next = cctxt->style->templates;
- cctxt->style->templates = templ;
- templ->match = xmlStrdup(BAD_CAST "/");
- /*
- * Note that we push the document-node in this special case.
- */
- xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
- /*
- * In every case, we need to have
- * the in-scope namespaces of the element, where the
- * stylesheet is rooted at, regardless if it's an XSLT
- * instruction or a literal result instruction (or if
- * this is an embedded stylesheet).
- */
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- /*
- * Parse the content and register the match-pattern.
- */
- xsltParseSequenceConstructor(cctxt, node);
- xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
- templ->elem = (xmlNodePtr) doc;
- templ->content = node;
- xsltAddTemplate(cctxt->style, templ, NULL, NULL);
- cctxt->style->literal_result = 1;
- return(0);
- }
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /**
- * xsltRestoreDocumentNamespaces:
- * @ns: map of namespaces
- * @doc: the document
- *
- * Restore the namespaces for the document
- *
- * Returns 0 in case of success, -1 in case of failure
- */
- int
- xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
- {
- if (doc == NULL)
- return(-1);
- /*
- * Revert the changes we have applied to the namespace-URIs of
- * ns-decls.
- */
- while (ns != NULL) {
- if ((ns->doc == doc) && (ns->ns != NULL)) {
- ns->ns->href = ns->origNsName;
- ns->origNsName = NULL;
- ns->ns = NULL;
- }
- ns = ns->next;
- }
- return(0);
- }
- #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
- /**
- * xsltParseStylesheetProcess:
- * @style: the XSLT stylesheet (the current stylesheet-level)
- * @doc: and xmlDoc parsed XML
- *
- * Parses an XSLT stylesheet, adding the associated structures.
- * Called by:
- * xsltParseStylesheetImportedDoc() (xslt.c)
- * xsltParseStylesheetInclude() (imports.c)
- *
- * Returns the value of the @style parameter if everything
- * went right, NULL if something went amiss.
- */
- xsltStylesheetPtr
- xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
- {
- xsltCompilerCtxtPtr cctxt;
- xmlNodePtr cur;
- int oldIsSimplifiedStylesheet;
- xsltInitGlobals();
- if ((style == NULL) || (doc == NULL))
- return(NULL);
- cctxt = XSLT_CCTXT(style);
- cur = xmlDocGetRootElement(doc);
- if (cur == NULL) {
- xsltTransformError(NULL, style, (xmlNodePtr) doc,
- "xsltParseStylesheetProcess : empty stylesheet\n");
- return(NULL);
- }
- oldIsSimplifiedStylesheet = cctxt->simplified;
- if ((IS_XSLT_ELEM(cur)) &&
- ((IS_XSLT_NAME(cur, "stylesheet")) ||
- (IS_XSLT_NAME(cur, "transform")))) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetProcess : found stylesheet\n");
- #endif
- cctxt->simplified = 0;
- style->literal_result = 0;
- } else {
- cctxt->simplified = 1;
- style->literal_result = 1;
- }
- /*
- * Pre-process the stylesheet if not already done before.
- * This will remove PIs and comments, merge adjacent
- * text nodes, internalize strings, etc.
- */
- if (! style->nopreproc)
- xsltParsePreprocessStylesheetTree(cctxt, cur);
- /*
- * Parse and compile the stylesheet.
- */
- if (style->literal_result == 0) {
- if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
- return(NULL);
- } else {
- if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
- return(NULL);
- }
- cctxt->simplified = oldIsSimplifiedStylesheet;
- return(style);
- }
- #else /* XSLT_REFACTORED */
- /**
- * xsltParseStylesheetProcess:
- * @ret: the XSLT stylesheet (the current stylesheet-level)
- * @doc: and xmlDoc parsed XML
- *
- * Parses an XSLT stylesheet, adding the associated structures.
- * Called by:
- * xsltParseStylesheetImportedDoc() (xslt.c)
- * xsltParseStylesheetInclude() (imports.c)
- *
- * Returns the value of the @style parameter if everything
- * went right, NULL if something went amiss.
- */
- xsltStylesheetPtr
- xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
- xmlNodePtr cur;
- xsltInitGlobals();
- if (doc == NULL)
- return(NULL);
- if (ret == NULL)
- return(ret);
- /*
- * First steps, remove blank nodes,
- * locate the xsl:stylesheet element and the
- * namespace declaration.
- */
- cur = xmlDocGetRootElement(doc);
- if (cur == NULL) {
- xsltTransformError(NULL, ret, (xmlNodePtr) doc,
- "xsltParseStylesheetProcess : empty stylesheet\n");
- return(NULL);
- }
- if ((IS_XSLT_ELEM(cur)) &&
- ((IS_XSLT_NAME(cur, "stylesheet")) ||
- (IS_XSLT_NAME(cur, "transform")))) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetProcess : found stylesheet\n");
- #endif
- ret->literal_result = 0;
- xsltParseStylesheetExcludePrefix(ret, cur, 1);
- xsltParseStylesheetExtPrefix(ret, cur, 1);
- } else {
- xsltParseStylesheetExcludePrefix(ret, cur, 0);
- xsltParseStylesheetExtPrefix(ret, cur, 0);
- ret->literal_result = 1;
- }
- if (!ret->nopreproc) {
- xsltPreprocessStylesheet(ret, cur);
- }
- if (ret->literal_result == 0) {
- xsltParseStylesheetTop(ret, cur);
- } else {
- xmlChar *prop;
- xsltTemplatePtr template;
- /*
- * the document itself might be the template, check xsl:version
- */
- prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(NULL, ret, cur,
- "xsltParseStylesheetProcess : document is not a stylesheet\n");
- return(NULL);
- }
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetProcess : document is stylesheet\n");
- #endif
- if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
- (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
- xsltTransformError(NULL, ret, cur,
- "xsl:version: only 1.1 features are supported\n");
- ret->forwards_compatible = 1;
- ret->warnings++;
- }
- xmlFree(prop);
- /*
- * Create and link the template
- */
- template = xsltNewTemplate();
- if (template == NULL) {
- return(NULL);
- }
- template->next = ret->templates;
- ret->templates = template;
- template->match = xmlStrdup((const xmlChar *)"/");
- /*
- * parse the content and register the pattern
- */
- xsltParseTemplateContent(ret, (xmlNodePtr) doc);
- template->elem = (xmlNodePtr) doc;
- template->content = doc->children;
- xsltAddTemplate(ret, template, NULL, NULL);
- ret->literal_result = 1;
- }
- return(ret);
- }
- #endif /* else of XSLT_REFACTORED */
- /**
- * xsltParseStylesheetImportedDoc:
- * @doc: an xmlDoc parsed XML
- * @parentStyle: pointer to the parent stylesheet (if it exists)
- *
- * parse an XSLT stylesheet building the associated structures
- * except the processing not needed for imported documents.
- *
- * Returns a new XSLT stylesheet structure.
- */
- xsltStylesheetPtr
- xsltParseStylesheetImportedDoc(xmlDocPtr doc,
- xsltStylesheetPtr parentStyle) {
- xsltStylesheetPtr retStyle;
- if (doc == NULL)
- return(NULL);
- retStyle = xsltNewStylesheetInternal(parentStyle);
- if (retStyle == NULL)
- return(NULL);
- if (xsltParseStylesheetUser(retStyle, doc) != 0) {
- xsltFreeStylesheet(retStyle);
- return(NULL);
- }
- return(retStyle);
- }
- /**
- * xsltParseStylesheetUser:
- * @style: pointer to the stylesheet
- * @doc: an xmlDoc parsed XML
- *
- * Parse an XSLT stylesheet with a user-provided stylesheet struct.
- *
- * Returns 0 if successful, -1 in case of error.
- */
- int
- xsltParseStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc) {
- if ((style == NULL) || (doc == NULL))
- return(-1);
- /*
- * Adjust the string dict.
- */
- if (doc->dict != NULL) {
- xmlDictFree(style->dict);
- style->dict = doc->dict;
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing dictionary from %s for stylesheet\n",
- doc->URL);
- #endif
- xmlDictReference(style->dict);
- }
- /*
- * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
- * the stylesheet to containt distinct namespace prefixes.
- */
- xsltGatherNamespaces(style);
- #ifdef XSLT_REFACTORED
- {
- xsltCompilerCtxtPtr cctxt;
- xsltStylesheetPtr oldCurSheet;
- if (style->parent == NULL) {
- xsltPrincipalStylesheetDataPtr principalData;
- /*
- * Create extra data for the principal stylesheet.
- */
- principalData = xsltNewPrincipalStylesheetData();
- if (principalData == NULL) {
- return(-1);
- }
- style->principalData = principalData;
- /*
- * Create the compilation context
- * ------------------------------
- * (only once; for the principal stylesheet).
- * This is currently the only function where the
- * compilation context is created.
- */
- cctxt = xsltCompilationCtxtCreate(style);
- if (cctxt == NULL) {
- return(-1);
- }
- style->compCtxt = (void *) cctxt;
- cctxt->style = style;
- cctxt->dict = style->dict;
- cctxt->psData = principalData;
- /*
- * Push initial dummy node info.
- */
- cctxt->depth = -1;
- xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
- } else {
- /*
- * Imported stylesheet.
- */
- cctxt = style->parent->compCtxt;
- style->compCtxt = cctxt;
- }
- /*
- * Save the old and set the current stylesheet structure in the
- * compilation context.
- */
- oldCurSheet = cctxt->style;
- cctxt->style = style;
- style->doc = doc;
- xsltParseStylesheetProcess(style, doc);
- cctxt->style = oldCurSheet;
- if (style->parent == NULL) {
- /*
- * Pop the initial dummy node info.
- */
- xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
- } else {
- /*
- * Clear the compilation context of imported
- * stylesheets.
- * TODO: really?
- */
- /* style->compCtxt = NULL; */
- }
- #ifdef XSLT_REFACTORED_XSLT_NSCOMP
- if (style->errors != 0) {
- /*
- * Restore all changes made to namespace URIs of ns-decls.
- */
- if (cctxt->psData->nsMap)
- xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
- }
- #endif
- if (style->parent == NULL) {
- xsltCompilationCtxtFree(style->compCtxt);
- style->compCtxt = NULL;
- }
- }
- #else /* XSLT_REFACTORED */
- /*
- * Old behaviour.
- */
- style->doc = doc;
- if (xsltParseStylesheetProcess(style, doc) == NULL) {
- style->doc = NULL;
- return(-1);
- }
- #endif /* else of XSLT_REFACTORED */
- if (style->errors != 0) {
- /*
- * Detach the doc from the stylesheet; otherwise the doc
- * will be freed in xsltFreeStylesheet().
- */
- style->doc = NULL;
- /*
- * Cleanup the doc if its the main stylesheet.
- */
- if (style->parent == NULL)
- xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
- return(-1);
- }
- if (style->parent == NULL)
- xsltResolveStylesheetAttributeSet(style);
- return(0);
- }
- /**
- * xsltParseStylesheetDoc:
- * @doc: and xmlDoc parsed XML
- *
- * parse an XSLT stylesheet, building the associated structures. doc
- * is kept as a reference within the returned stylesheet, so changes
- * to doc after the parsing will be reflected when the stylesheet
- * is applied, and the doc is automatically freed when the
- * stylesheet is closed.
- *
- * Returns a new XSLT stylesheet structure.
- */
- xsltStylesheetPtr
- xsltParseStylesheetDoc(xmlDocPtr doc) {
- xsltInitGlobals();
- return(xsltParseStylesheetImportedDoc(doc, NULL));
- }
- /**
- * xsltParseStylesheetFile:
- * @filename: the filename/URL to the stylesheet
- *
- * Load and parse an XSLT stylesheet
- *
- * Returns a new XSLT stylesheet structure.
- */
- xsltStylesheetPtr
- xsltParseStylesheetFile(const xmlChar* filename) {
- xsltSecurityPrefsPtr sec;
- xsltStylesheetPtr ret;
- xmlDocPtr doc;
- xsltInitGlobals();
- if (filename == NULL)
- return(NULL);
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetFile : parse %s\n", filename);
- #endif
- /*
- * Security framework check
- */
- sec = xsltGetDefaultSecurityPrefs();
- if (sec != NULL) {
- int res;
- res = xsltCheckRead(sec, NULL, filename);
- if (res <= 0) {
- if (res == 0)
- xsltTransformError(NULL, NULL, NULL,
- "xsltParseStylesheetFile: read rights for %s denied\n",
- filename);
- return(NULL);
- }
- }
- doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
- NULL, XSLT_LOAD_START);
- if (doc == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltParseStylesheetFile : cannot parse %s\n", filename);
- return(NULL);
- }
- ret = xsltParseStylesheetDoc(doc);
- if (ret == NULL) {
- xmlFreeDoc(doc);
- return(NULL);
- }
- return(ret);
- }
- /************************************************************************
- * *
- * Handling of Stylesheet PI *
- * *
- ************************************************************************/
- #define CUR (*cur)
- #define SKIP(val) cur += (val)
- #define NXT(val) cur[(val)]
- #define SKIP_BLANKS \
- while (IS_BLANK(CUR)) NEXT
- #define NEXT ((*cur) ? cur++ : cur)
- /**
- * xsltParseStylesheetPI:
- * @value: the value of the PI
- *
- * This function checks that the type is text/xml and extracts
- * the URI-Reference for the stylesheet
- *
- * Returns the URI-Reference for the stylesheet or NULL (it need to
- * be freed by the caller)
- */
- static xmlChar *
- xsltParseStylesheetPI(const xmlChar *value) {
- const xmlChar *cur;
- const xmlChar *start;
- xmlChar *val;
- xmlChar tmp;
- xmlChar *href = NULL;
- int isXml = 0;
- if (value == NULL)
- return(NULL);
- cur = value;
- while (CUR != 0) {
- SKIP_BLANKS;
- if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
- (NXT(3) == 'e')) {
- SKIP(4);
- SKIP_BLANKS;
- if (CUR != '=')
- continue;
- NEXT;
- if ((CUR != '\'') && (CUR != '"'))
- continue;
- tmp = CUR;
- NEXT;
- start = cur;
- while ((CUR != 0) && (CUR != tmp))
- NEXT;
- if (CUR != tmp)
- continue;
- val = xmlStrndup(start, cur - start);
- NEXT;
- if (val == NULL)
- return(NULL);
- if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
- (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
- xmlFree(val);
- break;
- }
- isXml = 1;
- xmlFree(val);
- } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
- (NXT(3) == 'f')) {
- SKIP(4);
- SKIP_BLANKS;
- if (CUR != '=')
- continue;
- NEXT;
- if ((CUR != '\'') && (CUR != '"'))
- continue;
- tmp = CUR;
- NEXT;
- start = cur;
- while ((CUR != 0) && (CUR != tmp))
- NEXT;
- if (CUR != tmp)
- continue;
- if (href == NULL)
- href = xmlStrndup(start, cur - start);
- NEXT;
- } else {
- while ((CUR != 0) && (!IS_BLANK(CUR)))
- NEXT;
- }
- }
- if (!isXml) {
- if (href != NULL)
- xmlFree(href);
- href = NULL;
- }
- return(href);
- }
- /**
- * xsltLoadStylesheetPI:
- * @doc: a document to process
- *
- * This function tries to locate the stylesheet PI in the given document
- * If found, and if contained within the document, it will extract
- * that subtree to build the stylesheet to process @doc (doc itself will
- * be modified). If found but referencing an external document it will
- * attempt to load it and generate a stylesheet from it. In both cases,
- * the resulting stylesheet and the document need to be freed once the
- * transformation is done.
- *
- * Returns a new XSLT stylesheet structure or NULL if not found.
- */
- xsltStylesheetPtr
- xsltLoadStylesheetPI(xmlDocPtr doc) {
- xmlNodePtr child;
- xsltStylesheetPtr ret = NULL;
- xmlChar *href = NULL;
- xmlURIPtr URI;
- xsltInitGlobals();
- if (doc == NULL)
- return(NULL);
- /*
- * Find the text/xml stylesheet PI id any before the root
- */
- child = doc->children;
- while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
- if ((child->type == XML_PI_NODE) &&
- (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
- href = xsltParseStylesheetPI(child->content);
- if (href != NULL)
- break;
- }
- child = child->next;
- }
- /*
- * If found check the href to select processing
- */
- if (href != NULL) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : found PI href=%s\n", href);
- #endif
- URI = xmlParseURI((const char *) href);
- if (URI == NULL) {
- xsltTransformError(NULL, NULL, child,
- "xml-stylesheet : href %s is not valid\n", href);
- xmlFree(href);
- return(NULL);
- }
- if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
- (URI->opaque == NULL) && (URI->authority == NULL) &&
- (URI->server == NULL) && (URI->user == NULL) &&
- (URI->path == NULL) && (URI->query == NULL)) {
- xmlAttrPtr ID;
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : Reference to ID %s\n", href);
- #endif
- if (URI->fragment[0] == '#')
- ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
- else
- ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
- if (ID == NULL) {
- xsltTransformError(NULL, NULL, child,
- "xml-stylesheet : no ID %s found\n", URI->fragment);
- } else {
- xmlDocPtr fake;
- xmlNodePtr subtree, newtree;
- xmlNsPtr ns;
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "creating new document from %s for embedded stylesheet\n",
- doc->URL);
- #endif
- /*
- * move the subtree in a new document passed to
- * the stylesheet analyzer
- */
- subtree = ID->parent;
- fake = xmlNewDoc(NULL);
- if (fake != NULL) {
- /*
- * Should the dictionary still be shared even though
- * the nodes are being copied rather than moved?
- */
- fake->dict = doc->dict;
- xmlDictReference(doc->dict);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing dictionary from %s for embedded stylesheet\n",
- doc->URL);
- #endif
- newtree = xmlDocCopyNode(subtree, fake, 1);
- fake->URL = xmlNodeGetBase(doc, subtree->parent);
- #ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "set base URI for embedded stylesheet as %s\n",
- fake->URL);
- #endif
- /*
- * Add all namespaces in scope of embedded stylesheet to
- * root element of newly created stylesheet document
- */
- while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
- for (ns = subtree->ns; ns; ns = ns->next) {
- xmlNewNs(newtree, ns->href, ns->prefix);
- }
- }
- xmlAddChild((xmlNodePtr)fake, newtree);
- ret = xsltParseStylesheetDoc(fake);
- if (ret == NULL)
- xmlFreeDoc(fake);
- }
- }
- } else {
- xmlChar *URL, *base;
- /*
- * Reference to an external stylesheet
- */
- base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
- URL = xmlBuildURI(href, base);
- if (URL != NULL) {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : fetching %s\n", URL);
- #endif
- ret = xsltParseStylesheetFile(URL);
- xmlFree(URL);
- } else {
- #ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : fetching %s\n", href);
- #endif
- ret = xsltParseStylesheetFile(href);
- }
- if (base != NULL)
- xmlFree(base);
- }
- xmlFreeURI(URI);
- xmlFree(href);
- }
- return(ret);
- }
|