PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/vyvoj.adent.cz/egroupware/khkstc/phpgwapi/inc
/srv/http/vyvoj.adent.cz/egroupware/khkstc/phpgwapi/inc/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/egroupware/khkstc/phpgwapi/inc/class.xml.inc.php
<?php

//
// +----------------------------------------------------------------------+
// | <phpXML/> version 1.0                                                |
// | Copyright (c) 2001 Michael P. Mehl. All rights reserved.             |
// +----------------------------------------------------------------------+
// | Latest releases are available at http://phpxml.org/. For feedback or |
// | bug reports, please contact the author at mpm@phpxml.org. Thanks!    |
// +----------------------------------------------------------------------+
// | The contents of this file are subject to the Mozilla Public License  |
// | Version 1.1 (the "License"); you may not use this file except in     |
// | compliance with the License. You may obtain a copy of the License at |
// | http://www.mozilla.org/MPL/                                          |
// |                                                                      |
// | Software distributed under the License is distributed on an "AS IS"  |
// | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See  |
// | the License for the specific language governing rights and           |
// | limitations under the License.                                       |
// |                                                                      |
// | The Original Code is <phpXML/>.                                      |
// |                                                                      |
// | The Initial Developer of the Original Code is Michael P. Mehl.       |
// | Portions created by Michael P. Mehl are Copyright (C) 2001 Michael   |
// | P. Mehl. All Rights Reserved.                                        |
// +----------------------------------------------------------------------+
// | Authors:                                                             |
// |   Michael P. Mehl <mpm@phpxml.org>                                   |
// +----------------------------------------------------------------------+
//

/**
* Class for accessing XML data through the XPath language.
*
* This class offers methods for accessing the nodes of a XML document using 
* the XPath language. You can add or remove nodes, set or modify their 
* content and their attributes. No additional PHP extensions like DOM XML 
* or something similar are required to use these features.
*
* @link      http://www.phpxml.org/ Latest release of this class
* @link      http://www.w3.org/TR/xpath W3C XPath Recommendation
* @copyright Copyright (c) 2001 Michael P. Mehl. All rights reserved.
* @author    Michael P. Mehl <mpm@phpxml.org>
* @version   1.0 (2001-03-08)
* @access    public
*/

class XML
{
    /**
    * List of all document nodes.
    *
    * This array contains a list of all document nodes saved as an
    * associative array.
    *
    * @access private
    * @var    array
    */
    var $nodes = array();
    
    /**
    * List of document node IDs.
    *
    * This array contains a list of all IDs of all document nodes that
    * are used for counting when adding a new node.
    *
    * @access private
    * @var    array
    */
    var $ids = array();
    
    /**
    * Current document path.
    *
    * This variable saves the current path while parsing a XML file and adding
    * the nodes being read from the file.
    *
    * @access private
    * @var    string
    */
    var $path = "";
    
    /**
    * Current document position.
    *
    * This variable counts the current document position while parsing a XML
    * file and adding the nodes being read from the file.
    *
    * @access private
    * @var    int
    */
    var $position = 0;
    
    /**
    * Path of the document root.
    *
    * This string contains the full path to the node that acts as the root
    * node of the whole document.
    *
    * @access private
    * @var    string
    */
    var $root = "";
    
    /**
    * Current XPath expression.
    *
    * This string contains the full XPath expression being parsed currently.
    *
    * @access private
    * @var    string
    */
    var $xpath    = "";
                                                                                
    /**
    * List of entities to be converted.
    *
    * This array contains a list of entities to be converted when an XPath
    * expression is evaluated.
    *
    * @access private
    * @var    array
    */
    var $entities = array ( "&" => "&amp;", "<" => "&lt;", ">" => "&gt;",
        "'" => "&apos", '"' => "&quot;" );
    
    /**
    * List of supported XPath axes.
    *
    * This array contains a list of all valid axes that can be evaluated in an
    * XPath expression.
    *
    * @access private
    * @var    array
    */
    var $axes = array ( "child", "descendant", "parent", "ancestor",
        "following-sibling", "preceding-sibling", "following", "preceding",
        "attribute", "namespace", "self", "descendant-or-self",
        "ancestor-or-self" );
    
    /**
    * List of supported XPath functions.
    *
    * This array contains a list of all valid functions that can be evaluated
    * in an XPath expression.
    *
    * @access private
    * @var    array
    */
    var $functions = array ( "last", "position", "count", "id", "name",
        "string", "concat", "starts-with", "contains", "substring-before",
        "substring-after", "substring", "string-length", "translate",
        "boolean", "not", "true", "false", "lang", "number", "sum", "floor",
        "ceiling", "round", "text" );
    
    /**
    * List of supported XPath operators.
    *
    * This array contains a list of all valid operators that can be evaluated
    * in a predicate of an XPath expression. The list is ordered by the
    * precedence of the operators (lowest precedence first).
    *
    * @access private
    * @var    array
    */
    var $operators = array( " or ", " and ", "=", "!=", "<=", "<", ">=", ">",
        "+", "-", "*", " div ", " mod " );

    /**
    * Constructor of the class.
    *
    * This constructor initializes the class and, when a filename is given,
    * tries to read and parse the given file.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $file Path and name of the file to read and parsed.
    * @see       load_file()
    */
    function XML ( $file = "" )
    {
        // Check whether a file was given.
        if ( !empty($file) )
        {
            // Load the XML file.
            $this->load_file($file);
        }
    }

    /**
    * Reads a file and parses the XML data.
    *
    * This method reads the content of a XML file, tries to parse its
    * content and upon success stores the information retrieved from
    * the file into an array.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $file Path and name of the file to be read and parsed.
    * @see       handle_start_element(), handle_end_element(),
    *            handle_character_data()
    */
    function load_file ( $file )
    {
        // Check whether the file exists and is readable.
        if ( file_exists($file) && is_readable($file) )
        {
            // Read the content of the file.
            $content = implode("", file($file));
            
            // Check whether content has been read.
            if ( !empty($content) )
            {
                // Create an XML parser.
                $parser = xml_parser_create();
                
                // Set the options for parsing the XML data.
                xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
                xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
                
                // Set the object for the parser.
                xml_set_object($parser, &$this);
                
                // Set the element handlers for the parser.
                xml_set_element_handler($parser, "handle_start_element",
                    "handle_end_element");
                xml_set_character_data_handler($parser,
                    "handle_character_data");
                
                // Parse the XML file.
                if ( !xml_parse($parser, $content, true) )
                {
                    // Display an error message.
                    $this->display_error("XML error in file %s, line %d: %s",
                        $file, xml_get_current_line_number($parser),
                        xml_error_string(xml_get_error_code($parser)));
                }
                
                // Free the parser.
                xml_parser_free($parser);
            }
        }
        else
        {
            // Display an error message.
            $this->display_error("File %s could not be found or read.", $file);
        }
    }
    
    /**
    * Generates a XML file with the content of the current document.
    *
    * This method creates a string containing the XML data being read
    * and modified by this class before. This string can be used to save
    * a modified document back to a file or doing other nice things with
    * it.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $highlight Array containing a list of full document
    *            paths of nodes to be highlighted by <font>...</font> tags
    *            in the generated XML string.
    * @param     string $root While doing a recursion with this method, this
    *            parameter is used for internal purpose.
    * @param     int $level While doing a recursion with this method, this
    *            parameter is used for internal purpose.
    * @return    string The returned string contains well-formed XML data
    *            representing the content of this document.
    * @see       load_file(), evaluate(), get_content()
    */
    function get_file ( $highlight = array(), $root = "", $level = 0 )
    {
        // Create a string to save the generated XML data.
        $xml = "";
        
        // Create two strings containing the tags for highlighting a node.
        $highlight_start = "<font color=\"#FF0000\"><b>";
        $highlight_end   = "</b></font>";
        
        // Generate a string to be displayed before the tags.
        $before = "";
        
        // Calculate the amount of whitespaces to display.
        for ( $i = 0; $i < ( $level * 2 ); $i++ )
        {
            // Add a whitespaces to the string.
            $before .= " ";
        }
        
        // Check whether a root node is given.
        if ( empty($root) )
        {
            // Set it to the document root.
            $root = $this->root;
        }
        
        // Check whether the node is selected.
        $selected = in_array($root, $highlight);
        
        // Now add the whitespaces to the XML data.
        $xml .= $before;
        
        // Check whether the node is selected.
        if ( $selected )
        {
            // Add the highlight code to the XML data.
            $xml .= $highlight_start;
        }
        
        // Now open the tag.
        $xml .= "&lt;".$this->nodes[$root]["name"];
        
        // Check whether there are attributes for this node.
        if ( count($this->nodes[$root]["attributes"]) > 0 )
        {
            // Run through all attributes.
            foreach ( $this->nodes[$root]["attributes"] as $key => $value )
            {
                // Check whether this attribute is highlighted.
                if ( in_array($root."/attribute::".$key, $highlight) )
                {
                    // Add the highlight code to the XML data.
                    $xml .= $highlight_start;
                }
                
                // Add the attribute to the XML data.
                $xml .= " ".$key."=\"".trim(stripslashes($value))."\"";
                
                // Check whether this attribute is highlighted.
                if ( in_array($root."/attribute::".$key, $highlight) )
                {
                    // Add the highlight code to the XML data.
                    $xml .= $highlight_end;
                }
            }
        }
        
        // Check whether the node contains character data or has children.
        if ( empty($this->nodes[$root]["text"]) &&
            !isset($this->nodes[$root]["children"]) )
        {
            // Add the end to the tag.
            $xml .= "/";
        }
        
        // Close the tag.
        $xml .= "&gt;\n";
        
        // Check whether the node is selected.
        if ( $selected )
        {
            // Add the highlight code to the XML data.
            $xml .= $highlight_end;
        }
        
        // Check whether the node contains character data.
        if ( !empty($this->nodes[$root]["text"]) )
        {
            // Add the character data to the XML data.
            $xml .= $before."  ".$this->nodes[$root]["text"]."\n";
        }
        
        // Check whether the node has children.
        if ( isset($this->nodes[$root]["children"]) )
        {
            // Run through all children with different names.
            foreach ( $this->nodes[$root]["children"] as $child => $pos )
            {
                // Run through all children with the same name.
                for ( $i = 1; $i <= $pos; $i++ )
                {
                    // Generate the full path of the child.
                    $fullchild = $root."/".$child."[".$i."]";
                    
                    // Add the child's XML data to the existing data.
                    $xml .= $this->get_file($highlight, $fullchild,
                        $level + 1);
                }
            }
        }
        
        // Check whether there are attributes for this node.
        if ( !empty($this->nodes[$root]["text"]) ||
            isset($this->nodes[$root]["children"]) )
        {
            // Add the whitespaces to the XML data.
            $xml .= $before;
            
            // Check whether the node is selected.
            if ( $selected )
            {
                // Add the highlight code to the XML data.
                $xml .= $highlight_start;
            }
            
            // Add the closing tag.
            $xml .= "&lt;/".$this->nodes[$root]["name"]."&gt;";
            
            // Check whether the node is selected.
            if ( $selected )
            {
                // Add the highlight code to the XML data.
                $xml .= $highlight_end;
            }
            
            // Add a linebreak.
            $xml .= "\n";
        }
        
        // Return the XML data.
        return $xml;
    }
    
    /**
    * Adds a new node to the XML document.
    *
    * This method adds a new node to the tree of nodes of the XML document
    * being handled by this class. The new node is created according to the
    * parameters passed to this method.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $content Full path of the parent, to which the new
    *            node should be added as a child.
    * @param     string $name Name of the new node.
    * @return    string The string returned by this method will contain the
    *            full document path of the created node.
    * @see       remove_node(), evaluate()
    */
    function add_node ( $context, $name )
    {
        // Check whether a name for this element is already set.
        if ( empty($this->root) )
        {
            // Use this tag as the root element.
            $this->root = "/".$name."[1]";
        }
        
        // Calculate the full path for this element.
        $path = $context."/".$name;
        
        // Set the relative context and the position.
        $position = ++$this->ids[$path];
        $relative = $name."[".$position."]";
        
        // Calculate the full path.
        $fullpath = $context."/".$relative;
        
        // Calculate the context position, which is the position of this
        // element within elements of the same name in the parent node.
        $this->nodes[$fullpath]["context-position"] = $position;
        
        // Calculate the position for the following and preceding axis
        // detection.
        $this->nodes[$fullpath]["document-position"] =
            $this->nodes[$context]["document-position"] + 1;
        
        // Save the information about the node.
        $this->nodes[$fullpath]["name"]   = $name;
        $this->nodes[$fullpath]["text"]   = "";
        $this->nodes[$fullpath]["parent"] = $context;
        
        // Add this element to the element count array.
        if ( !$this->nodes[$context]["children"][$name] )
        {
            // Set the default name.
            $this->nodes[$context]["children"][$name] = 1;
        }
        else
        {
            // Calculate the name.
            $this->nodes[$context]["children"][$name] =
                $this->nodes[$context]["children"][$name] + 1;
        }
        
        // Return the path of the new node.
        return $fullpath;
    }

    /**
    * Removes a node from the XML document.
    *
    * This method removes a node from the tree of nodes of the XML document.
    * If the node is a document node, all children of the node and its
    * character data will be removed. If the node is an attribute node,
    * only this attribute will be removed, the node to which the attribute
    * belongs as well as its children will remain unmodified.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node to be removed.
    * @see       add_node(), evaluate()
    */
    function remove_node ( $node )
    {
        // Check whether the node is an attribute node.
        if ( ereg("/attribute::", $node) )
        {
            // Get the path to the attribute node's parent.
            $parent = $this->prestr($node, "/attribute::");
            
            // Get the name of the attribute.
            $attribute = $this->afterstr($node, "/attribute::");
            
            // Check whether the attribute exists.
            if ( isset($this->nodes[$parent]["attributes"][$attribute]) )
            {
                // Create a new array.
                $new = array();
                
                // Run through the existing attributes.
                foreach ( $this->nodes[$parent]["attributes"]
                    as $key => $value )
                {
                    // Check whether it's the attribute to remove.
                    if ( $key != $attribute )
                    {
                        // Add it to the new array again.
                        $new[$key] = $value;
                    }
                }
                
                // Save the new attributes.
                $this->nodes[$parent]["attributes"] = $new;
            }
        }
        else
        {
            // Create an associative array, which contains information about
            // all nodes that required to be renamed.
            $rename = array();
            
            // Get the name, the parent and the siblings of current node.
            $name     = $this->nodes[$node]["name"];
            $parent   = $this->nodes[$node]["parent"];
            $siblings = $this->nodes[$parent]["children"][$name];
            
            // Decrease the number of children.
            $this->nodes[$parent]["children"][$name]--;
            
            // Create a counter for renumbering the siblings.
            $counter = 1;
            
            // Now run through the siblings.
            for ( $i = 1; $i <= $siblings; $i++ )
            {
                // Create the name of the sibling.
                $sibling = $parent."/".$name."[".$i."]";
                
                // Check whether it's the name of the current node.
                if ( $sibling != $node )
                {
                    // Create the new name for the sibling.
                    $new = $parent."/".$name."[".$counter."]";
                    
                    // Increase the counter.
                    $counter++;
                    
                    // Add the old and the new name to the list of nodes
                    // to be renamed.
                    $rename[$sibling] = $new;
                }
            }
            
            // Create an array for saving the new node-list.
            $nodes = array();
            
            // Now run through through the existing nodes.
            foreach ( $this->nodes as $name => $values )
            {
                // Check the position of the path of the node to be deleted
                // in the path of the current node.
                $position = strpos($name, $node);

                // Check whether it's not the node to be deleted.
                if ( $position === false )
                {
                    // Run through the array of nodes to be renamed.
                    foreach ( $rename as $old => $new )
                    {
                        // Check whether this node and it's parent requires to
                        // be renamed.
                        $name             = str_replace($old, $new, $name);
                        $values["parent"] = str_replace($old, $new,
                            $values["parent"]);
                    }
                    
                    // Add the node to the list of nodes.
                    $nodes[$name] = $values;
                }
            }
            
            // Save the new array of nodes.
            $this->nodes = $nodes;
        }
    }

    /**
    * Add content to a node.
    *
    * This method adds content to a node. If it's an attribute node, then
    * the value of the attribute will be set, otherwise the character data of
    * the node will be set. The content is appended to existing content,
    * so nothing will be overwritten.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node.
    * @param     string $value String containing the content to be added.
    * @see       get_content(), evaluate()
    */
    function add_content ( $path, $value )
    {
        // Check whether it's an attribute node.
        if ( ereg("/attribute::", $path) )
        {
            // Get the path to the attribute node's parent.
            $parent = $this->prestr($path, "/attribute::");
            
            // Get the parent node.
            $parent = $this->nodes[$parent];
            
            // Get the name of the attribute.
            $attribute = $this->afterstr($path, "/attribute::");
            
            // Set the attribute.
            $parent["attributes"][$attribute] .= $value;
        }
        else
        {
            // Set the character data of the node.
            $this->nodes[$path]["text"] .= $value;
        }
    }
    
    /**
    * Set the content of a node.
    *
    * This method sets the content of a node. If it's an attribute node, then
    * the value of the attribute will be set, otherwise the character data of
    * the node will be set. Existing content will be overwritten.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node.
    * @param     string $value String containing the content to be set.
    * @see       get_content(), evaluate()
    */
    function set_content ( $path, $value )
    {
        // Check whether it's an attribute node.
        if ( ereg("/attribute::", $path) )
        {
            // Get the path to the attribute node's parent.
            $parent = $this->prestr($path, "/attribute::");
            
            // Get the parent node.
            $parent = $this->nodes[$parent];
            
            // Get the name of the attribute.
            $attribute = $this->afterstr($path, "/attribute::");
            
            // Set the attribute.
            $parent["attributes"][$attribute] = $value;
        }
        else
        {
            // Set the character data of the node.
            $this->nodes[$path]["text"] = $value;
        }
    }
    
    /**
    * Retrieves the content of a node.
    *
    * This method retrieves the content of a node. If it's an attribute
    * node, then the value of the attribute will be retrieved, otherwise
    * it'll be the character data of the node.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node, from which the
    *            content should be retrieved.
    * @return    string The returned string contains either the value or the
    *            character data of the node.
    * @see       set_content(), evaluate()
    */
    function get_content ( $path )
    {
        // Check whether it's an attribute node.
        if ( ereg("/attribute::", $path) )
        {
            // Get the path to the attribute node's parent.
            $parent = $this->prestr($path, "/attribute::");
            
            // Get the parent node.
            $parent = $this->nodes[$parent];
            
            // Get the name of the attribute.
            $attribute = $this->afterstr($path, "/attribute::");
            
            // Get the attribute.
            $attribute = $parent["attributes"][$attribute];
            
            // Return the value of the attribute.
            return $attribute;
        }
        else
        {
            // Return the cdata of the node.
            return stripslashes($this->nodes[$path]["text"]);
        }
    }
    
    /**
    * Add attributes to a node.
    *
    * This method adds attributes to a node. Existing attributes will not be
    * overwritten.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node, the attributes
    *            should be added to.
    * @param     array $attributes Associative array containing the new
    *            attributes for the node.
    * @see       set_content(), get_content()
    */
    function add_attributes ( $path, $attributes )
    {
        // Add the attributes to the node.
        $this->nodes[$path]["attributes"] = array_merge($attributes,
            $this->nodes[$path]["attributes"]);
    }
    
    /**
    * Sets the attributes of a node.
    *
    * This method sets the attributes of a node and overwrites all existing
    * attributes by doing this.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node, the attributes
    *            of which should be set.
    * @param     array $attributes Associative array containing the new
    *            attributes for the node.
    * @see       set_content(), get_content()
    */
    function set_attributes ( $path, $attributes )
    {
        // Set the attributes of the node.
        $this->nodes[$path]["attributes"] = $attributes;
    }
    
    /**
    * Retrieves a list of all attributes of a node.
    *
    * This method retrieves a list of all attributes of the node specified in
    * the argument.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node, from which the
    *            list of attributes should be retrieved.
    * @return    array The returned associative array contains the all
    *            attributes of the specified node.
    * @see       get_content(), $nodes, $ids
    */
    function get_attributes ( $path )
    {
        // Return the attributes of the node.
        return $this->nodes[$path]["attributes"];
    }
    
    /**
    * Retrieves the name of a document node.
    *
    * This method retrieves the name of document node specified in the
    * argument.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path Full document path of the node, from which the
    *            name should be retrieved.
    * @return    string The returned array contains the name of the specified
    *            node.
    * @see       get_content(), $nodes, $ids
    */
    function get_name ( $path )
    {
        // Return the name of the node.
        return $this->nodes[$path]["name"];
    }
    
    /**
    * Evaluates an XPath expression.
    *
    * This method tries to evaluate an XPath expression by parsing it. A
    * XML document has to be read before this method is able to work.
    *
    * @access    public
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $path XPath expression to be evaluated.
    * @param     string $context Full path of a document node, starting
    *            from which the XPath expression should be evaluated.
    * @return    array The returned array contains a list of the full
    *            document paths of all nodes that match the evaluated
    *            XPath expression.
    * @see       $nodes, $ids
    */
    function evaluate ( $path, $context = "" )
    {
        // Remove slashes and quote signs.
        $path = stripslashes($path);
        $path = str_replace("\"", "", $path);
        $path = str_replace("'", "", $path);
        
        // Split the paths into different paths.
        $paths = $this->split_paths($path);
        
        // Create an empty set to save the result.
        $result = array();
        
        // Run through all paths.
        foreach ( $paths as $path )
        {
            // Trim the path.
            $path = trim($path);
            
            // Save the current path.
            $this->xpath = $path;
        
            // Convert all entities.
            $path = strtr($path, array_flip($this->entities));
        
            // Split the path at every slash.
            $steps = $this->split_steps($path);
        
            // Check whether the first element is empty.
            if ( empty($steps[0]) )
            {
                // Remove the first and empty element.
                array_shift($steps);
            }
        
            // Start to evaluate the steps.
            $nodes = $this->evaluate_step($context, $steps);
        
            // Remove duplicated nodes.
            $nodes = array_unique($nodes);
            
            // Add the nodes to the result set.
            $result = array_merge($result, $nodes);
        }
        
        // Return the result.
        return $result;
    }
    
    /**
    * Handles opening XML tags while parsing.
    *
    * While parsing a XML document for each opening tag this method is
    * called. It'll add the tag found to the tree of document nodes.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     int $parser Handler for accessing the current XML parser.
    * @param     string $name Name of the opening tag found in the document.
    * @param     array $attributes Associative array containing a list of
    *            all attributes of the tag found in the document.
    * @see       handle_end_element(), handle_character_data(), $nodes, $ids
    */
    function handle_start_element ( $parser, $name, $attributes )
    {
        // Add a node.
        $this->path = $this->add_node($this->path, $name);
        
        // Set the attributes.
        $this->set_attributes($this->path, $attributes);
    }
    
    /**
    * Handles closing XML tags while parsing.
    *
    * While parsing a XML document for each closing tag this method is
    * called.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     int $parser Handler for accessing the current XML parser.
    * @param     string $name Name of the closing tag found in the document.
    * @see       handle_start_element(), handle_character_data(), $nodes, $ids
    */
    function handle_end_element ( $parser, $name )
    {
        // Jump back to the parent element.
        $this->path = substr($this->path, 0, strrpos($this->path, "/"));
    }
    
    /**
    * Handles character data while parsing.
    *
    * While parsing a XML document for each character data this method
    * is called. It'll add the character data to the document tree.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     int $parser Handler for accessing the current XML parser.
    * @param     string $text Character data found in the document.
    * @see       handle_start_element(), handle_end_element(), $nodes, $ids
    */
    function handle_character_data ( $parser, $text )
    {
        // Replace entities.
        $text = strtr($text, $this->entities);
        
        // Save the text.
        $this->add_content($this->path, addslashes(trim($text)));
    }
    
    /**
    * Splits an XPath expression into its different expressions.
    *
    * This method splits an XPath expression. Each expression can consists of
    * list of expression being separated from each other by a | character.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $expression The complete expression to be splitted
    *            into its different expressions.
    * @return    array The array returned from this method contains a list
    *            of all expressions found in the expression passed to this
    *            method as a parameter.
    * @see       evalute()
    */
    function split_paths ( $expression )
    {
        // Create an empty array.
        $paths = array();
        
        // Save the position of the slash.
        $position = -1;
        
        // Run through the expression.
        do
        {
            // Search for a slash.
            $position = $this->search_string($expression, "|");
            
            // Check whether a | was found.
            if ( $position >= 0 )
            {
                // Get the left part of the expression.
                $left  = substr($expression, 0, $position);
                $right = substr($expression, $position + 1);
                
                // Add the left value to the steps.
                $paths[] = $left;
                
                // Reduce the expression to the right part.
                $expression = $right;
            }
        }
        while ( $position > -1 );
        
        // Add the remaing expression to the list of steps.
        $paths[] = $expression;
        
        // Return the steps.
        return $paths;
    }
    
    /**
    * Splits an XPath expression into its different steps.
    *
    * This method splits an XPath expression. Each expression can consists of
    * list of steps being separated from each other by a / character.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $expression The complete expression to be splitted
    *            into its different steps.
    * @return    array The array returned from this method contains a list
    *            of all steps found in the expression passed to this
    *            method as a parameter.
    * @see       evalute()
    */
    function split_steps ( $expression )
    {
        // Create an empty array.
        $steps = array();
        
        // Replace a double slashes, because they'll cause problems otherwise.
        $expression = str_replace("//@", "/descendant::*/@", $expression);
        $expression = str_replace("//", "/descendant::", $expression);
        
        // Save the position of the slash.
        $position = -1;
        
        // Run through the expression.
        do
        {
            // Search for a slash.
            $position = $this->search_string($expression, "/");
            
            // Check whether a slash was found.
            if ( $position >= 0 )
            {
                // Get the left part of the expression.
                $left  = substr($expression, 0, $position);
                $right = substr($expression, $position + 1);
                
                // Add the left value to the steps.
                $steps[] = $left;
                
                // Reduce the expression to the right part.
                $expression = $right;
            }
        }
        while ( $position > -1 );
        
        // Add the remaing expression to the list of steps.
        $steps[] = $expression;
        
        // Return the steps.
        return $steps;
    }
    
    /**
    * Retrieves axis information from an XPath expression step.
    *
    * This method tries to extract the name of the axis and its node-test
    * from a given step of an XPath expression at a given node.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $step String containing a step of an XPath expression.
    * @param     string $node Full document path of the node on which the
    *            step is executed.
    * @return    array This method returns an array containing information
    *            about the axis found in the step.
    * @see       evaluate_step()
    */
    function get_axis ( $step, $node )
    {
        // Create an array to save the axis information.
        $axis = array(
            "axis"      => "",
            "node-test" => "",
            "predicate" => array()
        );
        
        // Check whether there are predicates.
        if ( ereg("\[", $step) )
        {
            // Get the predicates.
            $predicates = substr($step, strpos($step, "["));
            
            // Reduce the step.
            $step = $this->prestr($step, "[");
            
            // Try to split the predicates.
            $predicates = str_replace("][", "]|[", $predicates);
            $predicates = explode("|", $predicates);
            
            // Run through all predicates.
            foreach ( $predicates as $predicate )
            {
                // Remove the brackets.
                $predicate = substr($predicate, 1, strlen($predicate) - 2);
                
                // Add the predicate to the list of predicates.
                $axis["predicate"][] = $predicate;
            }
        }
        
        // Check whether the axis is given in plain text.
        if ( $this->search_string($step, "::") > -1 )
        {
            // Split the step to extract axis and node-test.
            $axis["axis"]      = $this->prestr($step, "::");
            $axis["node-test"] = $this->afterstr($step, "::");
        }
        else
        {
            // Check whether the step is empty.
            if ( empty($step) )
            {
                // Set it to the default value.
                $step = ".";
            }
            
            // Check whether is an abbreviated syntax.
            if ( $step == "*" )
            {
                // Use the child axis and select all children.
                $axis["axis"]      = "child";
                $axis["node-test"] = "*";
            }
            elseif ( ereg("\(", $step) )
            {
                // Check whether it's a function.
                if ( $this->is_function($this->prestr($step, "(")) )
                {
                    // Get the position of the first bracket.
                    $start = strpos($step, "(");
                    $end   = strpos($step, ")", $start);
                    
                    // Get everything before, between and after the brackets.
                    $before  = substr($step, 0, $start);
                    $between = substr($step, $start + 1, $end - $start - 1);
                    $after   = substr($step, $end + 1);
                    
                    // Trim each string.
                    $before  = trim($before);
                    $between = trim($between);
                    $after   = trim($after);
                    
                    // Save the evaluated function.
                    $axis["axis"]      = "function";
                    $axis["node-test"] = $this->evaluate_function($before,
                        $between, $node);
                }
                else
                {
                    // Use the child axis and a function.
                    $axis["axis"]      = "child";
                    $axis["node-test"] = $step;
                }
            }
            elseif ( eregi("^@", $step) )
            {
                // Use the attribute axis and select the attribute.
                $axis["axis"]      = "attribute";
                $axis["node-test"] = substr($step, 1);
            }
            elseif ( eregi("\]$", $step) )
            {
                // Use the child axis and select a position.
                $axis["axis"]      = "child";
                $axis["node-test"] = substr($step, strpos($step, "["));
            }
            elseif ( $step == "." )
            {
                // Select the self axis.
                $axis["axis"]      = "self";
                $axis["node-test"] = "*";
            }
            elseif ( $step == ".." )
            {
                // Select the parent axis.
                $axis["axis"]      = "parent";
                $axis["node-test"] = "*";
            }
            elseif ( ereg("^[a-zA-Z0-9\-_]+$", $step) )
            {
                // Select the child axis and the child.
                $axis["axis"]      = "child";
                $axis["node-test"] = $step;
            }
            else
            {
                // Use the child axis and a name.
                $axis["axis"]      = "child";
                $axis["node-test"] = $step;
            }
        }

        // Check whether it's a valid axis.
        if ( !in_array($axis["axis"], array_merge($this->axes,
            array("function"))) )
        {
            // Display an error message.
            $this->display_error("While parsing an XPath expression, in ".
                "the step \"%s\" the invalid axis \"%s\" was found.",
                str_replace($step, "<b>".$step."</b>", $this->xpath),#
                $axis["axis"]);  
        }
        
        // Return the axis information.
        return $axis;
    }
    
    /**
    * Looks for a string within another string.
    *
    * This method looks for a string within another string. Brackets in the
    * string the method is looking through will be respected, which means that
    * only if the string the method is looking for is located outside of
    * brackets, the search will be successful.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $term String in which the search shall take place.
    * @param     string $expression String that should be searched.
    * @return    int This method returns -1 if no string was found, otherwise
    *            the offset at which the string was found.
    * @see       evaluate_step()
    */
    function search_string ( $term, $expression )
    {
        // Create a new counter for the brackets.
        $brackets = 0;
        
        // Run through the string.
        for ( $i = 0; $i < strlen($term); $i++ )
        {
            // Get the character at the position of the string.
            $character = substr($term, $i, 1);
            
            // Check whether it's a breacket.
            if ( ( $character == "(" ) || ( $character == "[" ) )
            {
                // Increase the number of brackets.
                $brackets++;
            }
            elseif ( ( $character == ")" ) || ( $character == "]" ) )
            {
                // Decrease the number of brackets.
                $brackets--;
            }
            elseif ( $brackets == 0 )
            {
                // Check whether we can find the expression at this index.
                if ( substr($term, $i, strlen($expression)) == $expression )
                {
                    // Return the current index.
                    return $i;
                }
            }
        }
        
        // Check whether we had a valid number of brackets.
        if ( $brackets != 0 )
        {
            // Display an error message.
            $this->display_error("While parsing an XPath expression, in the ".
                "predicate \"%s\", there was an invalid number of brackets.",
                str_replace($term, "<b>".$term."</b>", $this->xpath));
        }

        // Nothing was found.
        return (-1);
    }
    
    /**
    * Checks for a valid function name.
    *
    * This method check whether an expression contains a valid name of an
    * XPath function.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $expression Name of the function to be checked.
    * @return    boolean This method returns true if the given name is a valid
    *            XPath function name, otherwise false.
    * @see       evaluate()
    */
    function is_function ( $expression )
    {
        // Check whether it's in the list of supported functions.
        if ( in_array($expression, $this->functions) )
        {
            // It's a function.
            return true;
        }
        else
        {
            // It's not a function.
            return false;
        }
    }
    
    /**
    * Evaluates a step of an XPath expression.
    *
    * This method tries to evaluate a step from an XPath expression at a
    * specific context.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $context Full document path of the context from
    *            which starting the step should be evaluated.
    * @param     array $steps Array containing the remaining steps of the
    *            current XPath expression.
    * @return    array This method returns an array containing all nodes
    *            that are the result of evaluating the given XPath step.
    * @see       evaluate()
    */
    function evaluate_step ( $context, $steps )
    {
        // Create an empty array for saving the nodes found.
        $nodes = array();

        // Check whether the context is an array of contexts.
        if ( is_array($context) )
        {
            // Run through the array.
            foreach ( $context as $path )
            {
                // Call this method for this single path.
                $nodes = array_merge($nodes,
                    $this->evaluate_step($path, $steps));
            }
        }
        else
        {
            // Get this step.
            $step = array_shift($steps);
            
            // Create an array to save the new contexts.
            $contexts = array();
            
            // Get the axis of the current step.
            $axis = $this->get_axis($step, $context);
            
            // Check whether it's a function.
            if ( $axis["axis"] == "function" )
            {
                // Check whether an array was return by the function.
                if ( is_array($axis["node-test"]) )
                {
                    // Add the results to the list of contexts.
                    $contexts = array_merge($contexts, $axis["node-test"]);
                }
                else
                {
                    // Add the result to the list of contexts.
                    $contexts[] = $axis["node-test"];
                }
            }
            else
            {
                // Create the name of the method.
                $method = "handle_axis_".str_replace("-", "_", $axis["axis"]);
            
                // Check whether the axis handler is defined.
                if ( !method_exists(&$this, $method) )
                {
                    // Display an error message.
                    $this->display_error("While parsing an XPath expression, ".
                        "the axis \"%s\" could not be handled, because this ".
                        "version does not support this axis.", $axis["axis"]);
                }
            
                // Perform an axis action.
                $contexts = call_user_method($method, &$this, $axis, $context);
            
                // Check whether there are predicates.
                if ( count($axis["predicate"]) > 0 )
                {
                    // Check whether each node fits the predicates.
                    $contexts = $this->check_predicates($contexts,
                        $axis["predicate"]);
                }
            }
            
            // Check whether there are more steps left.
            if ( count($steps) > 0 )
            {
                // Continue the evaluation of the next steps.
                $nodes = $this->evaluate_step($contexts, $steps);
            }
            else
            {
                // Save the found contexts.
                $nodes = $contexts;
            }
        }
        
        // Return the nodes found.
        return $nodes;
    }
    
    /**
    * Evaluates an XPath function
    *
    * This method evaluates a given XPath function with its arguments on a
    * specific node of the document.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $function Name of the function to be evaluated.
    * @param     string $arguments String containing the arguments being
    *            passed to the function.
    * @param     string $node Full path to the document node on which the
    *            function should be evaluated.
    * @return    mixed This method returns the result of the evaluation of
    *            the function. Depending on the function the type of the 
    *            return value can be different.
    * @see       evaluate()
    */
    function evaluate_function ( $function, $arguments, $node )
    {
        // Remove whitespaces.
        $function  = trim($function);
        $arguments = trim($arguments);

        // Create the name of the function handling function.
        $method = "handle_function_".str_replace("-", "_", $function);
        
        // Check whether the function handling function is available.
        if ( !method_exists(&$this, $method) )
        {
            // Display an error message.
            $this->display_error("While parsing an XPath expression, ".
                "the function \"%s\" could not be handled, because this ".
                "version does not support this function.", $function);
        }
        
        // Return the result of the function.
        return call_user_method($method, &$this, $node, $arguments);
    }
    
    /**
    * Evaluates a predicate on a node.
    *
    * This method tries to evaluate a predicate on a given node.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the predicate
    *            should be evaluated.
    * @param     string $predicate String containing the predicate expression
    *            to be evaluated.
    * @return    mixed This method is called recursively. The first call should
    *            return a boolean value, whether the node matches the predicate
    *            or not. Any call to the method being made during the recursion
    *            may also return other types for further processing.
    * @see       evaluate()
    */
    function evaluate_predicate ( $node, $predicate )
    {
        // Set the default position and the type of the operator.
        $position = 0;
        $operator = "";
        
        // Run through all operators and try to find them.
        foreach ( $this->operators as $expression )
        {
            // Check whether a position was already found.
            if ( $position <= 0 )
            {
                // Try to find the operator.
                $position = $this->search_string($predicate, $expression);
            
                // Check whether a operator was found.
                if ( $position > 0 )
                {
                    // Save the operator.
                    $operator = $expression;
                    
                    // Check whether it's the equal operator.
                    if ( $operator == "=" )
                    {
                        // Also look for other operators containing the
                        // equal sign.
                        if ( $this->search_string($predicate, "!=") ==
                            ( $position - 1 ) )
                        {
                            // Get the new position.
                            $position = $this->search_string($predicate, "!=");
                            
                            // Save the new operator.
                            $operator = "!=";
                        }
                        if ( $this->search_string($predicate, "<=") ==
                            ( $position - 1 ) )
                        {
                            // Get the new position.
                            $position = $this->search_string($predicate, "<=");
                            
                            // Save the new operator.
                            $operator = "<=";
                        }
                        if ( $this->search_string($predicate, ">=") ==
                            ( $position - 1 ) )
                        {
                            // Get the new position.
                            $position = $this->search_string($predicate, ">=");
                            
                            // Save the new operator.
                            $operator = ">=";
                        }
                    }
                }
            }
        }
        
        // Check whether the operator is a - sign.
        if ( $operator == "-" )
        {
            // Check whether it's not a function containing a - in its name.
            foreach ( $this->functions as $function )
            {
                // Check whether there's a - sign in the function name.
                if ( ereg("-", $function) )
                {
                    // Get the position of the - in the function name.
                    $sign = strpos($function, "-");
                    
                    // Extract a substring from the predicate.
                    $sub = substr($predicate, $position - $sign,
                        strlen($function));
                        
                    // Check whether it's the function.
                    if ( $sub == $function )
                    {
                        // Don't use the operator.
                        $operator = "";
                        $position = -1;
                    }
                }
            }
        }
        elseif ( $operator == "*" )
        {
            // Get some substrings.
            $character = substr($predicate, $position - 1, 1);
            $attribute = substr($predicate, $position - 11, 11);
            
            // Check whether it's an attribute selection.
            if ( ( $character == "@" ) || ( $attribute == "attribute::" ) )
            {
                // Don't use the operator.
                $operator = "";
                $position = -1;
            }
        }
        
        // Check whether an operator was found.        
        if ( $position > 0 )
        {
            // Get the left and the right part of the expression.
            $left  = substr($predicate, 0, $position);
            $right = substr($predicate, $position + strlen($operator));
            
            // Remove whitespaces.
            $left  = trim($left);
            $right = trim($right);
            
            // Evaluate the left and the right part.
            $left  = $this->evaluate_predicate($node, $left);
            $right = $this->evaluate_predicate($node, $right);
            
            // Check the kind of operator.
            switch ( $operator )
            {
                case " or ":
                    // Return the two results connected by an "or".
                    return ( $left or $right );
                
                case " and ":
                    // Return the two results connected by an "and".
                    return ( $left and $right );
                
                case "=":
                    // Compare the two results.
                    return ( $left == $right );
                    
                case "!=":
                    // Check whether the two results are not equal.
                    return ( $left != $right );
                    
                case "<=":
                    // Compare the two results.
                    return ( $left <= $right );
                    
                case "<":
                    // Compare the two results.
                    return ( $left < $right );
                
                case ">=":
                    // Compare the two results.
                    return ( $left >= $right );
                    
                case ">":
                    // Compare the two results.
                    return ( $left > $right );
                    
                case "+":
                    // Return the result by adding one result to the other.
                    return ( $left + $right );
                
                case "-":
                    // Return the result by decrease one result by the other.
                    return ( $left - $right );
                
                case "*":
                    // Return a multiplication of the two results.
                    return ( $left * $right );
                    
                case " div ":
                    // Return a division of the two results.
                    if ( $right == 0 )
                    {
                        // Display an error message.
                        $this->display_error("While parsing an XPath ".
                            "predicate, a error due a division by zero ".
                            "occured.");
                    }
                    else
                    {
                        // Return the result of the division.
                        return ( $left / $right );
                    }
                    break;
                
                case " mod ":
                    // Return a modulo of the two results.
                    return ( $left % $right );
            }
        }
        
        // Check whether the predicate is a function.
        if ( ereg("\(", $predicate) )
        {
            // Get the position of the first bracket.
            $start = strpos($predicate, "(");
            $end   = strpos($predicate, ")", $start);
            
            // Get everything before, between and after the brackets.
            $before  = substr($predicate, 0, $start);
            $between = substr($predicate, $start + 1, $end - $start - 1);
            $after   = substr($predicate, $end + 1);
            
            // Trim each string.
            $before  = trim($before);
            $between = trim($between);
            $after   = trim($after);
            
            // Check whether there's something after the bracket.
            if ( !empty($after) )
            {
                // Display an error message.
                $this->display_error("While parsing an XPath expression ".
                    "there was found an error in the predicate \"%s\", ".
                    "because after a closing bracket there was found ".
                    "something unknown.", str_replace($predicate,
                    "<b>".$predicate."</b>", $this->xpath));
            }
            
            // Check whether it's a function.
            if ( empty($before) && empty($after) )
            {
                // Evaluate the content of the brackets.
                return $this->evaluate_predicate($node, $between);
            }
            elseif ( $this->is_function($before) )
            {
                // Return the evaluated function.
                return $this->evaluate_function($before, $between, $node);
            }
            else
            {
                // Display an error message.
                $this->display_error("While parsing a predicate in an XPath ".
                    "expression, a function \"%s\" was found, which is not ".
                    "yet supported by the parser.", str_replace($before,
                    "<b>".$before."</b>", $this->xpath));
            }
        }
        
        // Check whether the predicate is just a digit.
        if ( ereg("^[0-9]+(\.[0-9]+)?$", $predicate) ||
            ereg("^\.[0-9]+$", $predicate) )
        {
            // Return the value of the digit.
            return doubleval($predicate);
        }
        
        // Check whether it's an XPath expression.
        $result = $this->evaluate($predicate, $node);
        if ( count($result) > 0 )
        {
            // Convert the array.
            $result = explode("|", implode("|", $result));
            
            // Get the value of the first result.
            $value = $this->get_content($result[0]);
            
            // Return the value.
            return $value;
        }
        
        // Return the predicate as a string.
        return $predicate;
    }
    
    /**
    * Checks whether a node matches predicates.
    *
    * This method checks whether a list of nodes passed to this method match
    * a given list of predicates. 
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $nodes Array of full paths of all nodes to be tested.
    * @param     array $predicates Array of predicates to use.
    * @return    array The array returned by this method contains a list of
    *            all nodes matching the given predicates.
    * @see       evaluate_step()
    */
    function check_predicates ( $nodes, $predicates )
    {
        // Create an empty set of nodes.
        $result = array();
        
        // Run through all nodes.
        foreach ( $nodes as $node )
        {
            // Create a variable whether to add this node to the node-set.
            $add = true;
            
            // Run through all predicates.
            foreach ( $predicates as $predicate )
            {
                // Check whether the predicate is just an number.
                if ( ereg("^[0-9]+$", $predicate) )
                {
                    // Enhance the predicate.
                    $predicate .= "=position()";
                }
                
                // Do the predicate check.
                $check = $this->evaluate_predicate($node, $predicate);
                
                // Check whether it's a string.
                if ( is_string($check) && ( ( $check == "" ) ||
                    ( $check == $predicate ) ) )
                {
                    // Set the result to false.
                    $check = false;
                }
                
                // Check whether it's an integer.
                if ( is_int($check) )
                {
                    // Check whether it's the current position.
                    if ( $check == $this->handle_function_position($node, "") )
                    {
                        // Set it to true.
                        $check = true;
                    }
                    else
                    {
                        // Set it to false.
                        $check = false;
                    }
                }
                
                // Check whether the predicate is OK for this node.
                $add = $add && $check;
            }
            
            // Check whether to add this node to the node-set.
            if ( $add )
            {
                // Add the node to the node-set.
                $result[] = $node;
            }            
        }
        
        // Return the array of nodes.
        return $result;
    }
    
    /**
    * Checks whether a node matches a node-test.
    *
    * This method checks whether a node in the document matches a given
    * node-test.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $context Full path of the node, which should be tested
    *            for matching the node-test.
    * @param     string $node_test String containing the node-test for the
    *            node.
    * @return    boolean This method returns true if the node matches the
    *            node-test, otherwise false.
    * @see       evaluate()
    */
    function check_node_test ( $context, $node_test )
    {
        // Check whether it's a function.
        if ( ereg("\(", $node_test) )
        {
            // Get the type of function to use.
            $function = $this->prestr($node_test, "(");
            
            // Check whether the node fits the method.
            switch ( $function )
            {
                case "node":
                    // Add this node to the list of nodes.
                    return true;
                    
                case "text":
                    // Check whether the node has some text.
                    if ( !empty($this->nodes[$context]["text"]) )
                    {
                        // Add this node to the list of nodes.
                        return true;
                    }
                    break;
                    
                case "comment":
                    // Check whether the node has some comment.
                    if ( !empty($this->nodes[$context]["comment"]) )
                    {
                        // Add this node to the list of nodes.
                        return true;
                    }
                    break;
                
                case "processing-instruction":
                    // Get the literal argument.
                    $literal = $this->afterstr($axis["node-test"], "(");
                    
                    // Cut the literal.
                    $literal = substr($literal, 0, strlen($literal) - 1);
                    
                    // Check whether a literal was given.
                    if ( !empty($literal) )
                    {
                        // Check whether the node's processing instructions
                        // are matching the literals given.
                        if ( $this->nodes[$context]
                            ["processing-instructions"] == $literal )
                        {
                            // Add this node to the node-set.
                            return true;
                        }
                    }
                    else
                    {
                        // Check whether the node has processing
                        // instructions.
                        if ( !empty($this->nodes[$context]
                            ["processing-instructions"]) )
                        {
                            // Add this node to the node-set.
                            return true;
                        }
                    }
                    break;
                    
                default:
                    // Display an error message.
                    $this->display_error("While parsing an XPath ".
                        "expression there was found an undefined ".
                        "function called \"%s\".",
                        str_replace($function, "<b>".$function."</b>",
                        $this->xpath));
            }
        }
        elseif ( $node_test == "*" )
        {
            // Add this node to the node-set.
            return true;
        }
        elseif ( ereg("^[a-zA-Z0-9\-_]+", $node_test) )
        {
            // Check whether the node-test can be fulfilled.
            if ( $this->nodes[$context]["name"] == $node_test )
            {
                // Add this node to the node-set.
                return true;
            }
        }
        else
        {
            // Display an error message.
            $this->display_error("While parsing the XPath expression \"%s\" ".
                "an empty and therefore invalid node-test has been found.",
                $this->xpath);
        }
        
        // Don't add this context.
        return false;
    }
    
    /**
    * Handles the XPath child axis.
    *
    * This method handles the XPath child axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_child ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Get a list of all children.
        $children = $this->nodes[$context]["children"];
        
        // Check whether there are children.
        if ( !empty($children) )
        {
            // Run through all children.
            foreach ( $children as $child_name => $child_position )
            {
                // Run through all childs with this name.
                for ( $i = 1; $i <= $child_position; $i++ )
                {
                    // Create the path of the child.
                    $child = $context."/".$child_name."[".$i."]";
                    
                    // Check whether 
                    if ( $this->check_node_test($child, $axis["node-test"]) )
                    {
                        // Add the child to the node-set.
                        $nodes[] = $child;
                    }
                }
            }
        }
        
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath parent axis.
    *
    * This method handles the XPath parent axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_parent ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Check whether the parent matches the node-test.
        if ( $this->check_node_test($this->nodes[$context]["parent"],
            $axis["node-test"]) )
        {
            // Add this node to the list of nodes.
            $nodes[] = $this->nodes[$context]["parent"];
        }
        
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath attribute axis.
    *
    * This method handles the XPath attribute axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_attribute ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Check whether all nodes should be selected.
        if ( $axis["node-test"] == "*" )
        {
            // Check whether there are attributes.
            if ( count($this->nodes[$context]["attributes"]) > 0 )
            {
                // Run through the attributes.
                foreach ( $this->nodes[$context]["attributes"] as
                    $key => $value )
                {
                    // Add this node to the node-set.
                    $nodes[] = $context."/attribute::".$key;
                }
            }
        }
        elseif ( !empty($this->nodes[$context]["attributes"]
            [$axis["node-test"]]) )
        {
            // Add this node to the node-set.
            $nodes[] = $context."/attribute::".$axis["node-test"];
        }
            
        // Return the nodeset.
        return $nodes;
    }

    /**
    * Handles the XPath self axis.
    *
    * This method handles the XPath self axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_self ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Check whether the context match the node-test.
        if ( $this->check_node_test($context, $axis["node-test"]) )
        {
            // Add this node to the node-set.
            $nodes[] = $context;
        }

        // Return the nodeset.
        return $nodes;
    }

    /**
    * Handles the XPath descendant axis.
    *
    * This method handles the XPath descendant axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_descendant ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Check whether the current node has children.
        if ( count($this->nodes[$context]["children"]) > 0 )
        {
            // Get a list of children.
            $children = $this->nodes[$context]["children"];
            
            // Run through all children.
            foreach ( $children as $child_name => $child_position )
            {
                // Run through all children of this name.
                for ( $i = 1; $i <= $child_position; $i++ )
                {
                    // Create the full path for the children.
                    $child = $context."/".$child_name."[".$i."]";
                    
                    // Check whether the child matches the node-test.
                    if ( $this->check_node_test($child, $axis["node-test"]) )
                    {
                        // Add the child to the list of nodes.
                        $nodes[] = $child;
                    }
                    
                    // Recurse to the next level.
                    $nodes = array_merge($nodes,
                        $this->handle_axis_descendant($axis, $child));
                }
            }
        }
        
        // Return the nodeset.
        return $nodes;
    }

    /**
    * Handles the XPath ancestor axis.
    *
    * This method handles the XPath ancestor axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_ancestor ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Get the parent of the current node.
        $parent = $this->nodes[$context]["parent"];
        
        // Check whether the parent isn't empty.
        if ( !empty($parent) )
        {
            // Check whether the parent matches the node-test.
            if ( $this->check_node_test($parent, $axis["node-test"]) )
            {
                // Add the parent to the list of nodes.
                $nodes[] = $parent;
            }
            
            // Handle all other ancestors.
            $nodes = array_merge($nodes,
                $this->handle_axis_ancestor($axis, $parent));
        }
        
        // Return the nodeset.
        return $nodes;
    }

    /**
    * Handles the XPath namespace axis.
    *
    * This method handles the XPath namespace axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_namespace ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Check whether all nodes should be selected.
        if ( !empty($this->nodes[$context]["namespace"]) )
        {
            // Add this node to the node-set.
            $nodes[] = $context;
        }
            
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath following axis.
    *
    * This method handles the XPath following axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_following ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Get the current document position.
        $position = $this->nodes[$context]["document-position"];
        
        // Create a flag, whether we already found the context node.
        $found = false;
        
        // Run through all nodes of the document.
        foreach ( $this->nodes as $node => $data )
        {
            // Check whether the context node has already been found.
            if ( $found )
            {
                // Check whether the position is correct.
                if ( $this->nodes[$node]["document-position"] == $position )
                {
                    // Check whether the node fits the node-test.
                    if ( $this->check_node_test($node, $axis["node-test"]) )
                    {
                        // Add the node to the list of nodes.
                        $nodes[] = $node;
                    }
                }
            }
            
            // Check whether this is the context node.
            if ( $node == $context )
            {
                // After this we'll look for more nodes.
                $found = true;
            }
        }
            
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath preceding axis.
    *
    * This method handles the XPath preceding axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_preceding ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Get the current document position.
        $position = $this->nodes[$context]["document-position"];
        
        // Create a flag, whether we already found the context node.
        $found = true;
        
        // Run through all nodes of the document.
        foreach ( $this->nodes as $node => $data )
        {
            // Check whether this is the context node.
            if ( $node == $context )
            {
                // After this we won't look for more nodes.
                $found = false;
            }
            
            // Check whether the context node has already been found.
            if ( $found )
            {
                // Check whether the position is correct.
                if ( $this->nodes[$node]["document-position"] == $position )
                {
                    // Check whether the node fits the node-test.
                    if ( $this->check_node_test($node, $axis["node-test"]) )
                    {
                        // Add the node to the list of nodes.
                        $nodes[] = $node;
                    }
                }
            }
        }
            
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath following-sibling axis.
    *
    * This method handles the XPath following-sibling axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_following_sibling ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Get all children from the parent.
        $siblings = $this->handle_axis_child($axis,
            $this->nodes[$context]["parent"]);
        
        // Create a flag whether the context node was already found.
        $found = false;
        
        // Run through all siblings.
        foreach ( $siblings as $sibling )
        {
            // Check whether the context node was already found.
            if ( $found )
            {
                // Check whether the sibling is a real sibling.
                if ( $this->nodes[$sibling]["name"] ==
                    $this->nodes[$context]["name"] )
                {
                    // Check whether the sibling matches the node-test.
                    if ( $this->check_node_test($sibling, $axis["node-test"]) )
                    {
                        // Add the sibling to the list of nodes.
                        $nodes[] = $sibling;
                    }
                }
            }
            
            // Check whether this is the context node.
            if ( $sibling == $context )
            {
                // Continue looking for other siblings.
                $found = true;
            }
        }
            
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath preceding-sibling axis.
    *
    * This method handles the XPath preceding-sibling axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_preceding_sibling ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Get all children from the parent.
        $siblings = $this->handle_axis_child($axis,
            $this->nodes[$context]["parent"]);
        
        // Create a flag whether the context node was already found.
        $found = true;
        
        // Run through all siblings.
        foreach ( $siblings as $sibling )
        {
            // Check whether this is the context node.
            if ( $sibling == $context )
            {
                // Don't continue looking for other siblings.
                $found = false;
            }
            
            // Check whether the context node was already found.
            if ( $found )
            {
                // Check whether the sibling is a real sibling.
                if ( $this->nodes[$sibling]["name"] ==
                    $this->nodes[$context]["name"] )
                {
                    // Check whether the sibling matches the node-test.
                    if ( $this->check_node_test($sibling, $axis["node-test"]) )
                    {
                        // Add the sibling to the list of nodes.
                        $nodes[] = $sibling;
                    }
                }
            }
        }
            
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath descendant-or-self axis.
    *
    * This method handles the XPath descendant-or-self axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_descendant_or_self ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Read the nodes.
        $nodes = array_merge(
            $this->handle_axis_descendant($axis, $context),
            $this->handle_axis_self($axis, $context));
        
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath ancestor-or-self axis.
    *
    * This method handles the XPath ancestor-or-self axis.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     array $axis Array containing information about the axis.
    * @param     string $context Node from which starting the axis should
    *            be processed.
    * @return    array This method returns an array containing all nodes 
    *            that were found during the evaluation of the given axis.
    * @see       evaluate()
    */
    function handle_axis_ancestor_or_self ( $axis, $context )
    {
        // Create an empty node-set.
        $nodes = array();
        
        // Read the nodes.
        $nodes = array_merge(
            $this->handle_axis_ancestor($axis, $context),
            $this->handle_axis_self($axis, $context));
        
        // Return the nodeset.
        return $nodes;
    }
    
    /**
    * Handles the XPath function last.
    *
    * This method handles the XPath function last.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_last ( $node, $arguments )
    {
        // Calculate the size of the context.
        $parent   = $this->nodes[$node]["parent"];
        $children = $this->nodes[$parent]["children"];
        $context  = $children[$this->nodes[$node]["name"]];

        // Return the size.
        return $context;
    }

    /**
    * Handles the XPath function position.
    *
    * This method handles the XPath function position.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_position ( $node, $arguments )
    {
        // return the context-position.
        return $this->nodes[$node]["context-position"];
    }
    
    /**
    * Handles the XPath function count.
    *
    * This method handles the XPath function count.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_count ( $node, $arguments )
    {
        // Evaluate the argument of the method as an XPath and return
        // the number of results.
        return count($this->evaluate($arguments, $node));
    }
    
    /**
    * Handles the XPath function id.
    *
    * This method handles the XPath function id.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_id ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Now split the arguments.
        $arguments = explode(" ", $arguments);
        
        // Check whether 
        
        // Create a list of nodes.
        $nodes = array();
        
        // Run through all document node.
        foreach ( $this->nodes as $node => $position )
        {
            // Check whether the node has the ID we're looking for.
            if ( in_array($this->nodes[$node]["attributes"]["id"],
                $arguments) )
            {
                // Add this node to the list of nodes.
                $nodes[] = $node;
            }
        }
        
        // Return the list of nodes.
        return $nodes;
    }
    
    /**
    * Handles the XPath function name.
    *
    * This method handles the XPath function name.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_name ( $node, $arguments )
    {
        // Return the name of the node.
        return $this->nodes[$node]["name"];
    }
    
    /**
    * Handles the XPath function string.
    *
    * This method handles the XPath function string.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_string ( $node, $arguments )
    {
        // Check what type of parameter is given
        if ( ereg("^[0-9]+(\.[0-9]+)?$", $arguments) ||
            ereg("^\.[0-9]+$", $arguments) )
        {
            // Convert the digits to a number.
            $number = doubleval($arguments);
                
            // Return the number.
            return strval($number);
        }
        elseif ( is_bool($arguments) )
        {
            // Check whether it's true.
            if ( $arguments == true )
            {
                // Return true as a string.
                return "true";
            }
            else
            {
                // Return false as a string.
                return "false";
            }
        }
        elseif ( !empty($arguments) )
        {
            // Use the argument as an XPath.
            $result = $this->evaluate($arguments, $node);
                
            // Get the first argument.
            $result = explode("|", implode("|", $result));
                
            // Return the first result as a string.
            return $result[0];
        }
        elseif ( empty($arguments) )
        {
            // Return the current node.
            return $node;
        }
        else
        {
            // Return an empty string.
            return "";
        }
    }
    
    /**
    * Handles the XPath function concat.
    *
    * This method handles the XPath function concat.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_concat ( $node, $arguments )
    {
        // Split the arguments.
        $arguments = explode(",", $arguments);
            
        // Run through each argument and evaluate it.
        for ( $i = 0; $i < sizeof($arguments); $i++ )
        {
            // Trim each argument.
            $arguments[$i] = trim($arguments[$i]);
                
            // Evaluate it.
            $arguments[$i] = $this->evaluate_predicate($node, $arguments[$i]);
        }
            
        // Put the string together.
        $arguments = implode("", $arguments);
            
        // Return the string.
        return $arguments;
    }
    
    /**
    * Handles the XPath function starts-with.
    *
    * This method handles the XPath function starts-with.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_starts_with ( $node, $arguments )
    {
        // Get the arguments.
        $first  = trim($this->prestr($arguments, ","));
        $second = trim($this->afterstr($arguments, ","));
            
        // Evaluate each argument.
        $first  = $this->evaluate_predicate($node, $first);
        $second = $this->evaluate_predicate($node, $second);
            
        // Check whether the first string starts with the second one.
        if ( ereg("^".$second, $first) )
        {
            // Return true.
            return true;
        }
        else
        {
            // Return false.
            return false;
        }
    }
    
    /**
    * Handles the XPath function contains.
    *
    * This method handles the XPath function contains.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_contains ( $node, $arguments )
    {
        // Get the arguments.
        $first  = trim($this->prestr($arguments, ","));
        $second = trim($this->afterstr($arguments, ","));
            
        // Evaluate each argument.
        $first  = $this->evaluate_predicate($node, $first);
        $second = $this->evaluate_predicate($node, $second);
            
        // Check whether the first string starts with the second one.
        if ( ereg($second, $first) )
        {
            // Return true.
            return true;
        }
        else
        {
            // Return false.
            return false;
        }
    }
    
    /**
    * Handles the XPath function substring-before.
    *
    * This method handles the XPath function substring-before.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_substring_before ( $node, $arguments )
    {
        // Get the arguments.
        $first  = trim($this->prestr($arguments, ","));
        $second = trim($this->afterstr($arguments, ","));
          
        // Evaluate each argument.
        $first  = $this->evaluate_predicate($node, $first);
        $second = $this->evaluate_predicate($node, $second);
            
        // Return the substring.
        return $this->prestr(strval($first), strval($second));
    }
    
    /**
    * Handles the XPath function substring-after.
    *
    * This method handles the XPath function substring-after.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_substring_after ( $node, $arguments )
    {
        // Get the arguments.
        $first  = trim($this->prestr($arguments, ","));
        $second = trim($this->afterstr($arguments, ","));
            
        // Evaluate each argument.
        $first  = $this->evaluate_predicate($node, $first);
        $second = $this->evaluate_predicate($node, $second);
            
        // Return the substring.
        return $this->afterstr(strval($first), strval($second));
    }
    
    /**
    * Handles the XPath function substring.
    *
    * This method handles the XPath function substring.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_substring ( $node, $arguments )
    {
        // Split the arguments.
        $arguments = explode(",", $arguments);
            
        // Run through all arguments.
        for ( $i = 0; $i < sizeof($arguments); $i++ )
        {
            // Trim the string.
            $arguments[$i] = trim($arguments[$i]);
                
            // Evaluate each argument.
            $arguments[$i] = $this->evaluate_predicate($node, $arguments[$i]);
        }
            
        // Check whether a third argument was given.
        if ( !empty($arguments[2]) )
        {
            // Return the substring.
            return substr(strval($arguments[0]), $arguments[1] - 1,
                $arguments[2]);
        }
        else
        {
            // Return the substring.
            return substr(strval($arguments[0]), $arguments[1] - 1);
        }
    }
    
    /**
    * Handles the XPath function string-length.
    *
    * This method handles the XPath function string-length.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_string_length ( $node, $arguments )
    {
        // Trim the argument.
        $arguments = trim($arguments);
            
        // Evaluate the argument.
        $arguments = $this->evaluate_predicate($node, $arguments);
            
        // Return the length of the string.
        return strlen(strval($arguments));
    }
    
    /**
    * Handles the XPath function translate.
    *
    * This method handles the XPath function translate.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_translate ( $node, $arguments )         
    {
        // Split the arguments.
        $arguments = explode(",", $arguments);
        
        // Run through all arguments.
        for ( $i = 0; $i < sizeof($arguments); $i++ )
        {
            // Trim the argument.
            $arguments[$i] = trim($arguments[$i]);
            
            // Evaluate the argument.
            $arguments[$i] = $this->evaluate_predicate($node, $arguments[$i]);
        }
            
        // Return the translated string.
        return strtr($arguments[0], $arguments[1], $arguments[2]);
    }
    
    /**
    * Handles the XPath function boolean.
    *
    * This method handles the XPath function boolean.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_boolean ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Check what type of parameter is given
        if ( ereg("^[0-9]+(\.[0-9]+)?$", $arguments) ||
            ereg("^\.[0-9]+$", $arguments) )
        {
            // Convert the digits to a number.
            $number = doubleval($arguments);
            
            // Check whether the number zero.
            if ( $number == 0 )
            {
                // Return false.
                return false;
            }
            else
            {
                // Return true.
                return true;
            }
        }
        elseif ( empty($arguments) )
        {
            // Sorry, there were no arguments.
            return false;
        }
        else
        {
            // Try to evaluate the argument as an XPath.
            $result = $this->evaluate($arguments, $node);
            
            // Check whether we found something.
            if ( count($result) > 0 )
            {
                // Return true.
                return true;
            }
            else
            {
                // Return false.
                return false;
            }
        }
    }
    
    /**
    * Handles the XPath function not.
    *
    * This method handles the XPath function not.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_not ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Return the negative value of the content of the brackets.
        return !$this->evaluate_predicate($node, $arguments);
    }
    
    /**
    * Handles the XPath function true.
    *
    * This method handles the XPath function true.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_true ( $node, $arguments )
    {
        // Return true.
        return true;
    }
    
    /**
    * Handles the XPath function false.
    *
    * This method handles the XPath function false.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_false ( $node, $arguments )
    {
        // Return false.
        return false;
    }
    
    /**
    * Handles the XPath function lang.
    *
    * This method handles the XPath function lang.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_lang ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Check whether the node has an language attribute.
        if ( empty($this->nodes[$node]["attributes"]["xml:lang"]) )
        {
            // Run through the ancestors.
            while ( !empty($node) )
            {
                // Select the parent node.
                $node = $this->nodes[$node]["parent"];
                
                // Check whether there's a language definition.
                if ( !empty($this->nodes[$node]["attributes"]["xml:lang"]) )
                {
                    // Check whether it's the language, the user asks for.
                    if ( eregi("^".$arguments, $this->nodes[$node]
                        ["attributes"]["xml:lang"]) )
                    {
                        // Return true.
                        return true;
                    }
                    else
                    {
                        // Return false.
                        return false;
                    }
                }
            }
            
            // Return false.
            return false;
        }
        else
        {
            // Check whether it's the language, the user asks for.
            if ( eregi("^".$arguments, $this->nodes[$node]["attributes"]
                ["xml:lang"]) )
            {
                // Return true.
                return true;
            }
            else
            {
                // Return false.
                return false;
            }
        }
    }
    
    /**
    * Handles the XPath function number.
    *
    * This method handles the XPath function number.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_number ( $node, $arguments )
    {
        // Check the type of argument.
        if ( ereg("^[0-9]+(\.[0-9]+)?$", $arguments) ||
            ereg("^\.[0-9]+$", $arguments) )
        {
            // Return the argument as a number.
            return doubleval($arguments);
        }
        elseif ( is_bool($arguments) )
        {
            // Check whether it's true.
            if ( $arguments == true )
            {
                // Return 1.
                return 1;
            }
            else
            {
                // Return 0.
                return 0;
            }
        }
    }
    
    /**
    * Handles the XPath function sum.
    *
    * This method handles the XPath function sum.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_sum ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Evaluate the arguments as an XPath expression.
        $results = $this->evaluate($arguments, $node);
        
        // Create a variable to save the sum.
        $sum = 0;
        
        // Run through all results.
        foreach ( $results as $result )
        {
            // Get the value of the node.
            $result = $this->get_content($result);
            
            // Add it to the sum.
            $sum += doubleval($result);
        }
        
        // Return the sum.
        return $sum;
    }
    
    /**
    * Handles the XPath function floor.
    *
    * This method handles the XPath function floor.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_floor ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Convert the arguments to a number.
        $arguments = doubleval($arguments);
        
        // Return the result
        return floor($arguments);
    }
    
    /**
    * Handles the XPath function ceiling.
    *
    * This method handles the XPath function ceiling.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_ceiling ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Convert the arguments to a number.
        $arguments = doubleval($arguments);
        
        // Return the result
        return ceil($arguments);
    }
    
    /**
    * Handles the XPath function round.
    *
    * This method handles the XPath function round.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_round ( $node, $arguments )
    {
        // Trim the arguments.
        $arguments = trim($arguments);
        
        // Convert the arguments to a number.
        $arguments = doubleval($arguments);
        
        // Return the result
        return round($arguments);
    }
    
    /**
    * Handles the XPath function text.
    *
    * This method handles the XPath function text.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $node Full path of the node on which the function
    *            should be processed.
    * @param     string $arguments String containing the arguments that were
    *            passed to the function.
    * @return    mixed Depending on the type of function being processed this 
    *            method returns different types.
    * @see       evaluate()
    */
    function handle_function_text ( $node, $arguments )
    {
        // Return the character data of the node.
        return $this->nodes[$node]["text"];
    }
    
    /**
    * Retrieves a substring before a delimiter.
    *
    * This method retrieves everything from a string before a given delimiter,
    * not including the delimiter.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $string String, from which the substring should be
    *            extracted.
    * @param     string $delimiter String containing the delimiter to use.
    * @return    string Substring from the original string before the
    *            delimiter.
    * @see       afterstr()
    */
    function prestr ( $string, $delimiter )
    {
        // Return the substring.
		return substr($string, 0, strlen($string) - strlen(@strstr($string,$delimiter)));
	}
    
    /**
    * Retrieves a substring after a delimiter.
    *
    * This method retrieves everything from a string after a given delimiter,
    * not including the delimiter.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $string String, from which the substring should be
    *            extracted.
    * @param     string $delimiter String containing the delimiter to use.
    * @return    string Substring from the original string after the
    *            delimiter.
    * @see       prestr()
    */
    function afterstr ( $string, $delimiter )
    {
        // Return the substring.
		return substr($string,
            strpos($string, $delimiter) + strlen($delimiter));
	}
    
    /**
    * Displays an error message.
    *
    * This method displays an error messages and stops the execution of the
    * script. This method is called exactly in the same way as the printf
    * function. The first argument contains the message and additional
    * arguments of various types may be passed to this method to be inserted
    * into the message.
    *
    * @access    private
    * @author    Michael P. Mehl <mpm@phpxml.org>
    * @param     string $message Error message to be displayed.
    */
    function display_error ( $message )
    {
		// Check whether more than one argument was given.
		if ( func_num_args() > 1 )
		{
			// Read all arguments.
			$arguments = func_get_args();
			
			// Create a new string for the inserting command.
			$command = "\$message = sprintf(\$message, ";
			
			// Run through the array of arguments.
			for ( $i = 1; $i < sizeof($arguments); $i++ )
			{
				// Add the number of the argument to the command.
				$command .= "\$arguments[".$i."], ";
			}
			
			// Replace the last separator.
			$command = eregi_replace(", $", ");", $command);
			
			// Execute the command.
			eval($command);
		}
		
        // Display the error message.
        echo "<b>phpXML error:</b> ".$message;
        
        // End the execution of this script.
        exit;
    }
}

?>