XML.Mod 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864
  1. MODULE XML; (** AUTHOR "swalthert"; PURPOSE "XML base"; *)
  2. IMPORT
  3. Streams, Strings, UTF8Strings, Modules, DynamicStrings, Objects := XMLObjects, KernelLog;
  4. CONST
  5. Ok* = 0;
  6. InvalidString* = 1;
  7. BufferError* = 2;
  8. Tab = DynamicStrings.Tab;
  9. Space = 20X;
  10. TYPE
  11. String* = Strings.String;
  12. TYPE
  13. Content* = OBJECT
  14. VAR
  15. pos: LONGINT;
  16. previous, next : Content;
  17. PROCEDURE &Init*;
  18. BEGIN
  19. pos := 0;
  20. previous := NIL; next := NIL;
  21. END Init;
  22. PROCEDURE GetPos*(): LONGINT;
  23. BEGIN
  24. RETURN pos
  25. END GetPos;
  26. PROCEDURE SetPos*(pos : LONGINT);
  27. BEGIN
  28. SELF.pos := pos
  29. END SetPos;
  30. (** write the content to stream w. level is the current hierarchy level. used for formatting *)
  31. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  32. END Write;
  33. END Content;
  34. NameContent* = OBJECT (Content)
  35. VAR
  36. name: String;
  37. PROCEDURE &Init*;
  38. BEGIN
  39. Init^;
  40. name := StrNoName;
  41. END Init;
  42. PROCEDURE GetName*(): String;
  43. BEGIN
  44. RETURN name
  45. END GetName;
  46. PROCEDURE SetName*(CONST name: ARRAY OF CHAR);
  47. BEGIN
  48. SELF.name := NewString(name)
  49. END SetName;
  50. PROCEDURE SetNameAsString*(name : String);
  51. BEGIN
  52. IF (name # NIL) THEN
  53. SELF.name := name;
  54. ELSE
  55. SELF.name := StrNoName;
  56. END;
  57. END SetNameAsString;
  58. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  59. BEGIN
  60. w.String(name^)
  61. END Write;
  62. END NameContent;
  63. Container* = OBJECT (Content)
  64. VAR
  65. first, last : Content;
  66. nofContents : LONGINT;
  67. PROCEDURE &Init*;
  68. BEGIN
  69. Init^;
  70. first := NIL; last := NIL;
  71. nofContents := 0;
  72. END Init;
  73. PROCEDURE RemoveContent0(c: Content): BOOLEAN;
  74. VAR cur : Content;
  75. BEGIN
  76. (*ASSERT(c # NIL);*)
  77. IF c=NIL THEN RETURN FALSE END;(*PH 12/13*)
  78. IF (first # NIL) THEN
  79. IF (first = c) THEN
  80. IF (first.next # NIL) THEN first.next.previous := NIL; END;
  81. first := first.next;
  82. IF (last = c) THEN last := NIL; ASSERT(first = NIL); END;
  83. c.next := NIL; c.previous := NIL;
  84. RETURN TRUE
  85. ELSE
  86. cur := first;
  87. WHILE (cur.next # NIL) & (cur.next # c) DO cur := cur.next; END;
  88. IF (cur.next # NIL) THEN
  89. IF (cur.next.next # NIL) THEN cur.next.next.previous := cur; END;
  90. cur.next := cur.next.next;
  91. IF (last = c) THEN last := cur; ASSERT(cur.next = NIL); END;
  92. c.next := NIL; c.previous := NIL;
  93. RETURN TRUE
  94. END;
  95. END;
  96. END;
  97. RETURN FALSE
  98. END RemoveContent0;
  99. (* Move this after previous. If previous = NIL then move this to end *)
  100. PROCEDURE MoveContentAfter*(this, previous: Content);
  101. VAR current: Content;
  102. BEGIN{EXCLUSIVE}
  103. IF RemoveContent0(this) THEN
  104. IF (previous = NIL) OR (previous = last) THEN (* insert as last *)
  105. IF last = NIL THEN
  106. first := this; last := this
  107. ELSE
  108. last.next := this;
  109. this.previous := last;
  110. last := this;
  111. END;
  112. ELSE
  113. this.next := previous.next;
  114. this.next.previous := this;
  115. previous.next := this;
  116. this.previous := previous;
  117. END
  118. END;
  119. END MoveContentAfter;
  120. (* Move this before next. If next = NIL then move this to front *)
  121. PROCEDURE MoveContentBefore*(this, next: Content);
  122. VAR current: Content;
  123. BEGIN{EXCLUSIVE}
  124. IF RemoveContent0(this) THEN
  125. IF (next = NIL) OR (next = first) THEN (* insert as first *)
  126. IF first = NIL THEN
  127. first := this; last := this
  128. ELSE
  129. this.next := first;
  130. first.previous := this;
  131. first := this;
  132. END;
  133. ELSE
  134. next.previous.next := this;
  135. this.previous := next.previous;
  136. this.next := next;
  137. next.previous := this;
  138. END;
  139. END;
  140. END MoveContentBefore;
  141. PROCEDURE AddContent*(c: Content);
  142. BEGIN {EXCLUSIVE}
  143. ASSERT((c # NIL) & (c.next = NIL) & (c.previous = NIL)); (* may not be in more than one list! *)
  144. IF (first = NIL) THEN
  145. ASSERT(last = NIL);
  146. first := c; last := c;
  147. ELSE
  148. ASSERT(last # NIL);
  149. last.next := c;
  150. c.previous := last;
  151. last := c;
  152. END;
  153. ASSERT((first # NIL) & (last # NIL));
  154. INC(nofContents);
  155. END AddContent;
  156. PROCEDURE RemoveContent*(c: Content);
  157. VAR b: BOOLEAN;
  158. BEGIN {EXCLUSIVE}
  159. IF RemoveContent0(c) THEN DEC(nofContents) END
  160. END RemoveContent;
  161. PROCEDURE GetContents*(): Objects.Enumerator;
  162. VAR c : Content; array : Objects.PTRArray; enumerator : Objects.ArrayEnumerator; i : LONGINT;
  163. BEGIN {EXCLUSIVE}
  164. NEW(array, nofContents);
  165. c := first;
  166. FOR i := 0 TO nofContents - 1 DO
  167. array[i] := c;
  168. c := c.next;
  169. END;
  170. NEW(enumerator, array);
  171. RETURN enumerator;
  172. END GetContents;
  173. PROCEDURE GetNumberOfContents*(): LONGINT;
  174. BEGIN
  175. RETURN nofContents;
  176. END GetNumberOfContents;
  177. PROCEDURE GetFirst*() : Content;
  178. BEGIN
  179. RETURN first;
  180. END GetFirst;
  181. PROCEDURE GetLast*() : Content;
  182. BEGIN
  183. RETURN last;
  184. END GetLast;
  185. PROCEDURE GetNext*(content : Content) : Content;
  186. BEGIN
  187. ASSERT(content # NIL);
  188. RETURN content.next;
  189. END GetNext;
  190. PROCEDURE GetPrevious*(content : Content) : Content;
  191. BEGIN
  192. ASSERT(content # NIL);
  193. RETURN content.previous;
  194. END GetPrevious;
  195. END Container;
  196. TYPE
  197. Document* = OBJECT (Container)
  198. VAR
  199. xmldecl: XMLDecl;
  200. dtd: DocTypeDecl;
  201. root: Element;
  202. PROCEDURE &Init*;
  203. BEGIN
  204. Init^;
  205. xmldecl := NIL;
  206. NEW(dtd);
  207. root := NIL;
  208. END Init;
  209. PROCEDURE GetXMLDecl*(): XMLDecl;
  210. BEGIN
  211. RETURN xmldecl
  212. END GetXMLDecl;
  213. PROCEDURE GetDocTypeDecl*(): DocTypeDecl;
  214. BEGIN
  215. RETURN dtd
  216. END GetDocTypeDecl;
  217. PROCEDURE GetRoot*(): Element;
  218. BEGIN
  219. RETURN root
  220. END GetRoot;
  221. PROCEDURE AddContent*(c: Content);
  222. BEGIN
  223. IF (c IS XMLDecl) & (xmldecl = NIL) THEN xmldecl := c(XMLDecl)
  224. ELSIF (c IS DocTypeDecl) THEN dtd := c(DocTypeDecl)
  225. ELSIF (c IS Element) & (root = NIL) THEN root := c(Element); root.SetDocument(SELF)
  226. END;
  227. AddContent^(c)
  228. END AddContent;
  229. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  230. VAR e: Objects.Enumerator; c: ANY;
  231. BEGIN
  232. e := GetContents();
  233. WHILE e.HasMoreElements() DO
  234. c := e.GetNext();
  235. c(Content).Write(w, context, level + 1)
  236. END
  237. END Write;
  238. END Document;
  239. TextDecl* = OBJECT (Content)
  240. VAR
  241. version, encoding: String;
  242. PROCEDURE &Init*;
  243. BEGIN
  244. Init^;
  245. version := NIL; encoding := NIL;
  246. END Init;
  247. PROCEDURE GetVersion*(): String;
  248. BEGIN
  249. RETURN version
  250. END GetVersion;
  251. PROCEDURE SetVersion*(CONST version: ARRAY OF CHAR);
  252. BEGIN
  253. SELF.version := NewString(version)
  254. END SetVersion;
  255. PROCEDURE GetEncoding*(): String;
  256. BEGIN
  257. RETURN encoding
  258. END GetEncoding;
  259. PROCEDURE SetEncoding*(CONST encoding: ARRAY OF CHAR);
  260. BEGIN
  261. SELF.encoding := NewString(encoding)
  262. END SetEncoding;
  263. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  264. BEGIN
  265. w.String('<?xml version="'); w.String(version^);
  266. IF encoding # NIL THEN w.String('" encoding="'); w.String(encoding^) END;
  267. w.String('"?>'); NewLine(w, level)
  268. END Write;
  269. END TextDecl;
  270. XMLDecl* = OBJECT (TextDecl)
  271. VAR
  272. standalone: BOOLEAN;
  273. PROCEDURE &Init*;
  274. BEGIN
  275. Init^;
  276. standalone := FALSE;
  277. END Init;
  278. PROCEDURE IsStandalone*(): BOOLEAN;
  279. BEGIN
  280. RETURN standalone
  281. END IsStandalone;
  282. PROCEDURE SetStandalone*(standalone: BOOLEAN);
  283. BEGIN
  284. SELF.standalone := standalone
  285. END SetStandalone;
  286. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  287. BEGIN
  288. w.String('<?xml version="'); w.String(version^);
  289. IF encoding # NIL THEN w.String('" encoding="'); w.String(encoding^) END;
  290. w.String('" standalone="');
  291. IF standalone THEN w.String("yes") ELSE w.String("no") END;
  292. w.String('"?>'); NewLine(w, level)
  293. END Write;
  294. END XMLDecl;
  295. DocTypeDecl* = OBJECT (NameContent)
  296. VAR
  297. elementDecls, notationDecls, generalEntities, parameterEntities: Objects.Dictionary;
  298. allMarkupDecls: Objects.Collection;
  299. externalSubset: EntityDecl;
  300. PROCEDURE & Init*;
  301. VAR (* ed: EntityDecl; *) arrDict: Objects.ArrayDict; arrColl: Objects.ArrayCollection;
  302. BEGIN
  303. Init^;
  304. NEW(arrDict); elementDecls := arrDict;
  305. NEW(arrDict); notationDecls := arrDict;
  306. NEW(arrDict); generalEntities := arrDict;
  307. NEW(arrDict); parameterEntities := arrDict;
  308. NEW(arrColl); allMarkupDecls := arrColl;
  309. externalSubset := NIL;
  310. (* add predefined entities *)
  311. (* NEW(ed); NEW(ed.name, 3); ed.name[0] := 'l'; ed.name[1] := 't'; ed.name[2] := 0X;
  312. NEW(ed.value, 10); COPY("&#38;#60;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
  313. NEW(ed); NEW(ed.name, 3); ed.name[0] := 'g'; ed.name[1] := 't'; ed.name[2] := 0X;
  314. NEW(ed.value, 10); COPY("&#62;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
  315. NEW(ed); NEW(ed.name, 4); ed.name[0] := 'a'; ed.name[1] := 'm'; ed.name[2] := 'p'; ed.name[3] := 0X;
  316. NEW(ed.value, 10); COPY("&#38;#38;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
  317. NEW(ed); NEW(ed.name, 5); ed.name[0] := 'a'; ed.name[1] := 'p'; ed.name[2] := 'o'; ed.name[3] := 's'; ed.name[4] := 0X;
  318. NEW(ed.value, 10); COPY("&#39;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
  319. NEW(ed); NEW(ed.name, 5); ed.name[0] := 'q'; ed.name[1] := 'u'; ed.name[2] := 'o'; ed.name[3] := 't'; ed.name[4] := 0X;
  320. NEW(ed.value, 10); COPY("&#34;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed)
  321. *)
  322. END Init;
  323. PROCEDURE AddMarkupDecl*(c: Content);
  324. BEGIN
  325. IF c IS ElementDecl THEN
  326. elementDecls.Add(c(ElementDecl).name^, c); allMarkupDecls.Add(c)
  327. ELSIF (c IS EntityDecl) & (c(EntityDecl).type = GeneralEntity) THEN
  328. generalEntities.Add(c(EntityDecl).name^, c); allMarkupDecls.Add(c)
  329. ELSIF (c IS EntityDecl) & (c(EntityDecl).type = ParameterEntity) THEN
  330. parameterEntities.Add(c(EntityDecl).name^, c); allMarkupDecls.Add(c)
  331. ELSIF c IS NotationDecl THEN
  332. notationDecls.Add(c(NotationDecl).name^, c); allMarkupDecls.Add(c)
  333. ELSIF (c IS ProcessingInstruction) OR (c IS Comment) THEN
  334. allMarkupDecls.Add(c)
  335. END
  336. END AddMarkupDecl;
  337. PROCEDURE GetElementDecl*(CONST name: ARRAY OF CHAR): ElementDecl;
  338. VAR p: ANY;
  339. BEGIN
  340. p := elementDecls.Get(name);
  341. IF p # NIL THEN RETURN p(ElementDecl)
  342. ELSE RETURN NIL
  343. END
  344. END GetElementDecl;
  345. PROCEDURE GetNotationDecl*(CONST name: ARRAY OF CHAR): NotationDecl;
  346. VAR p: ANY;
  347. BEGIN
  348. p := elementDecls.Get(name);
  349. IF p # NIL THEN RETURN p(NotationDecl)
  350. ELSE RETURN NIL
  351. END
  352. END GetNotationDecl;
  353. PROCEDURE GetEntityDecl*(CONST name: ARRAY OF CHAR; type: SHORTINT): EntityDecl;
  354. VAR p: ANY;
  355. BEGIN
  356. p := NIL;
  357. IF type = GeneralEntity THEN p := generalEntities.Get(name)
  358. ELSIF type = ParameterEntity THEN p := parameterEntities.Get(name)
  359. END;
  360. IF p # NIL THEN RETURN p(EntityDecl)
  361. ELSE RETURN NIL
  362. END
  363. END GetEntityDecl;
  364. PROCEDURE GetExternalSubset*(): EntityDecl;
  365. BEGIN
  366. RETURN externalSubset
  367. END GetExternalSubset;
  368. PROCEDURE SetExternalSubset*(externalSubset: EntityDecl);
  369. BEGIN
  370. SELF.externalSubset := externalSubset
  371. END SetExternalSubset;
  372. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  373. VAR e: Objects.Enumerator; p: ANY; s: String;
  374. BEGIN
  375. w.String("<!DOCTYPE "); w.String(name^);
  376. IF externalSubset # NIL THEN
  377. s := externalSubset.GetPublicId();
  378. IF s # NIL THEN
  379. w.String(' PUBLIC "'); w.String(s^); w.String('" "');
  380. ELSE
  381. w.String(' SYSTEM "')
  382. END;
  383. s := externalSubset.GetSystemId();
  384. w.String(s^); w.Char('"')
  385. END;
  386. e := allMarkupDecls.GetEnumerator();
  387. IF e.HasMoreElements() THEN
  388. w.String(" ["); NewLine(w, level + 1);
  389. WHILE e.HasMoreElements() DO
  390. p := e.GetNext(); p(Content).Write(w, context, level + 1)
  391. END;
  392. w.String("]")
  393. END;
  394. w.Char('>'); NewLine(w, level)
  395. END Write;
  396. END DocTypeDecl;
  397. NotationDecl* = OBJECT (NameContent)
  398. VAR
  399. systemId, publicId: String;
  400. PROCEDURE &Init*;
  401. BEGIN
  402. Init^;
  403. systemId := NIL; publicId := NIL;
  404. END Init;
  405. PROCEDURE GetSystemId*(): String;
  406. BEGIN
  407. RETURN systemId
  408. END GetSystemId;
  409. PROCEDURE SetSystemId*(CONST systemId: ARRAY OF CHAR);
  410. BEGIN
  411. SELF.systemId := NewString(systemId)
  412. END SetSystemId;
  413. PROCEDURE GetPublicId*(): String;
  414. BEGIN
  415. RETURN publicId
  416. END GetPublicId;
  417. PROCEDURE SetPublicId*(CONST publicId: ARRAY OF CHAR);
  418. BEGIN
  419. SELF.publicId := NewString(publicId)
  420. END SetPublicId;
  421. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  422. BEGIN
  423. w.String("<!NOTATION "); w.String(name^);
  424. IF publicId # NIL THEN
  425. w.String(' PUBLIC "'); w.String(publicId^); w.String('" "');
  426. IF systemId # NIL THEN w.String(systemId^); w.Char('"') END
  427. ELSE
  428. w.String(' SYSTEM "'); w.String(systemId^); w.Char('"')
  429. END;
  430. w.Char('>'); NewLine(w, level)
  431. END Write;
  432. END NotationDecl;
  433. CONST
  434. (** EntityDecl.SetType *)
  435. GeneralEntity* = 0;
  436. ParameterEntity* = 1;
  437. TYPE
  438. EntityDecl* = OBJECT (NotationDecl)
  439. VAR
  440. value, notationName: String;
  441. type: SHORTINT;
  442. PROCEDURE &Init*;
  443. BEGIN
  444. Init^;
  445. value := NIL; notationName := NIL;
  446. type := GeneralEntity;
  447. END Init;
  448. PROCEDURE GetType*(): SHORTINT;
  449. BEGIN
  450. RETURN type
  451. END GetType;
  452. PROCEDURE SetType*(type: SHORTINT);
  453. BEGIN
  454. SELF.type := type
  455. END SetType;
  456. PROCEDURE GetValue*(): String;
  457. BEGIN
  458. RETURN value
  459. END GetValue;
  460. PROCEDURE SetValue*(CONST value: ARRAY OF CHAR);
  461. BEGIN
  462. SELF.value := NewString(value)
  463. END SetValue;
  464. PROCEDURE GetNotationName*(): String;
  465. BEGIN
  466. RETURN notationName
  467. END GetNotationName;
  468. PROCEDURE SetNotationName*(CONST notationName: ARRAY OF CHAR);
  469. BEGIN
  470. SELF.notationName := NewString(notationName)
  471. END SetNotationName;
  472. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  473. BEGIN
  474. w.String("<!ENTITY ");
  475. IF type = ParameterEntity THEN w.String("% ") END;
  476. w.String(name^);
  477. IF value # NIL THEN
  478. w.String(' "'); w.String(value^); w.Char('"')
  479. ELSE
  480. IF publicId # NIL THEN
  481. w.String(' PUBLIC "'); w.String(publicId^); w.String('" "');
  482. IF systemId # NIL THEN w.String(systemId^); w.Char('"') END
  483. ELSE
  484. w.String(' SYSTEM "'); w.String(systemId^); w.Char('"')
  485. END;
  486. IF (type = GeneralEntity) & (notationName # NIL) THEN
  487. w.String(' NDATA '); w.String(notationName^)
  488. END
  489. END;
  490. w.Char('>'); NewLine(w, level)
  491. END Write;
  492. END EntityDecl;
  493. CONST
  494. (** ElementDecl.SetContentType *)
  495. Any* = 0; (** 'ANY' *)
  496. Empty* = 1; (** 'EMPTY' *)
  497. ElementContent* = 2; (** children *)
  498. MixedContent* = 3; (** Mixed *)
  499. TYPE
  500. ElementDecl* = OBJECT (NameContent)
  501. VAR
  502. contentType: SHORTINT;
  503. content: CollectionCP; (* for contentType = Mixed or contentType = Element *)
  504. attributeDecls: Objects.Dictionary;
  505. PROCEDURE & Init*;
  506. VAR arrDict: Objects.ArrayDict;
  507. BEGIN
  508. Init^;
  509. contentType := Any;
  510. content := NIL;
  511. NEW(arrDict); attributeDecls := arrDict
  512. END Init;
  513. PROCEDURE GetContentType*(): SHORTINT;
  514. BEGIN
  515. RETURN contentType
  516. END GetContentType;
  517. PROCEDURE SetContentType*(contentType: SHORTINT);
  518. BEGIN
  519. SELF.contentType := contentType
  520. END SetContentType;
  521. PROCEDURE GetContent*(): CollectionCP;
  522. BEGIN
  523. RETURN content
  524. END GetContent;
  525. PROCEDURE SetContent*(lcp: CollectionCP);
  526. BEGIN
  527. content := lcp
  528. END SetContent;
  529. PROCEDURE GetAttributeDecl*(CONST name: ARRAY OF CHAR): AttributeDecl;
  530. VAR nc: ANY;
  531. BEGIN
  532. nc := attributeDecls.Get(name);
  533. IF nc # NIL THEN RETURN nc (AttributeDecl) ELSE RETURN NIL END
  534. END GetAttributeDecl;
  535. PROCEDURE GetAttributeDecls*(): Objects.Enumerator;
  536. BEGIN
  537. RETURN attributeDecls.GetEnumerator()
  538. END GetAttributeDecls;
  539. PROCEDURE AddAttributeDecl*(attributeDecl: AttributeDecl);
  540. BEGIN
  541. attributeDecls.Add(attributeDecl.name^, attributeDecl)
  542. END AddAttributeDecl;
  543. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  544. VAR e: Objects.Enumerator; p: ANY;
  545. BEGIN
  546. w.String("<!ELEMENT "); w.String(name^); w.Char(Space);
  547. IF contentType = Empty THEN
  548. w.String("EMPTY")
  549. ELSIF contentType = Any THEN
  550. w.String("ANY")
  551. ELSIF content # NIL THEN
  552. content.Write(w, context, level + 1)
  553. END;
  554. w.Char('>'); NewLine(w, level);
  555. e := GetAttributeDecls();
  556. IF e.HasMoreElements() THEN
  557. w.String("<!ATTLIST "); w.String(name^); NewLine(w, level+1);
  558. WHILE e.HasMoreElements() DO
  559. p := e.GetNext(); p(Content).Write(w, context, level + 1)
  560. END;
  561. w.Char('>'); NewLine(w, level)
  562. END
  563. END Write;
  564. END ElementDecl;
  565. CONST
  566. (** ContentParticle.SetOccurence *)
  567. ZeroOrOnce* = 0; (** '?' *)
  568. ZeroOrMore* = 1; (** '*' *)
  569. Once* = 2; (** nothing *)
  570. OnceOrMore* = 3; (** '+' *)
  571. TYPE
  572. ContentParticle* = OBJECT (Content)
  573. VAR
  574. occurence: SHORTINT;
  575. PROCEDURE &Init*;
  576. BEGIN
  577. Init^;
  578. occurence := ZeroOrOnce;
  579. END Init;
  580. PROCEDURE GetOccurence*(): SHORTINT;
  581. BEGIN
  582. RETURN occurence
  583. END GetOccurence;
  584. PROCEDURE SetOccurence*(occ: SHORTINT);
  585. BEGIN
  586. occurence := occ
  587. END SetOccurence;
  588. PROCEDURE GetOccurenceChar(): CHAR;
  589. BEGIN
  590. CASE occurence OF
  591. | ZeroOrOnce: RETURN '?'
  592. | ZeroOrMore: RETURN '*'
  593. | Once: RETURN 0X
  594. | OnceOrMore: RETURN '+'
  595. END
  596. END GetOccurenceChar;
  597. END ContentParticle;
  598. NameContentParticle* = OBJECT (ContentParticle)
  599. VAR
  600. name: String;
  601. PROCEDURE &Init*;
  602. BEGIN
  603. Init^;
  604. name := NIL;
  605. END Init;
  606. PROCEDURE GetName*(): String;
  607. BEGIN
  608. RETURN name
  609. END GetName;
  610. PROCEDURE SetName*(CONST name: ARRAY OF CHAR);
  611. BEGIN
  612. SELF.name := NewString(name)
  613. END SetName;
  614. PROCEDURE SetNameAsString*(name : String);
  615. BEGIN
  616. SELF.name := name;
  617. END SetNameAsString;
  618. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  619. VAR ch: CHAR;
  620. BEGIN
  621. w.String(name^);
  622. ch := GetOccurenceChar(); IF ch # 0X THEN w.Char(ch) END
  623. END Write;
  624. END NameContentParticle;
  625. CONST
  626. (** CollectionCP.SetType *)
  627. Choice* = 1;
  628. Sequence* = 2;
  629. TYPE
  630. CollectionCP* = OBJECT (ContentParticle)
  631. VAR
  632. children: Objects.Collection;
  633. type: SHORTINT;
  634. PROCEDURE & Init*;
  635. VAR arrColl: Objects.ArrayCollection;
  636. BEGIN
  637. Init^;
  638. NEW(arrColl); children := arrColl;
  639. type := 0;
  640. END Init;
  641. PROCEDURE GetType*(): SHORTINT;
  642. BEGIN
  643. RETURN type
  644. END GetType;
  645. PROCEDURE SetType*(type: SHORTINT);
  646. BEGIN
  647. SELF.type := type
  648. END SetType;
  649. PROCEDURE GetChildren*(): Objects.Enumerator;
  650. BEGIN
  651. RETURN children.GetEnumerator()
  652. END GetChildren;
  653. PROCEDURE AddChild*(cp: ContentParticle);
  654. BEGIN
  655. children.Add(cp)
  656. END AddChild;
  657. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  658. VAR e: Objects.Enumerator; ch: CHAR; p: ANY;
  659. BEGIN
  660. e := GetChildren();
  661. p := e.GetNext();
  662. w.Char('(');
  663. p(Content).Write(w, context, level + 1);
  664. WHILE e.HasMoreElements() DO
  665. p := e.GetNext();
  666. IF type = Choice THEN w.String(" | ")
  667. ELSIF type = Sequence THEN w.String(", ")
  668. END;
  669. p(Content).Write(w, context, level + 1)
  670. END;
  671. w.Char(')');
  672. ch := GetOccurenceChar(); IF ch # 0X THEN w.Char(ch) END
  673. END Write;
  674. END CollectionCP;
  675. CONST
  676. (** AttributeDecl.SetType *)
  677. CData* = 0; (** CDATA *)
  678. Id* = 1; (** ID *)
  679. IdRef* = 2; (** IDREF *)
  680. IdRefs* = 3; (** IDREFS *)
  681. Entity* = 4; (** ENTITY *)
  682. Entities* = 5; (** ENTITIES *)
  683. NmToken* = 6; (** NMTOKEN *)
  684. NmTokens* = 7; (** NMTOKENS *)
  685. Notation* = 8; (** NOTATION *)
  686. Enumeration* = 9; (** Enumeration *)
  687. TYPE
  688. AttributeDecl* = OBJECT (NameContent)
  689. VAR
  690. defaultValue: String;
  691. type: SHORTINT;
  692. allowedValues: Objects.Dictionary;
  693. required: BOOLEAN;
  694. PROCEDURE &Init*;
  695. VAR arrDict: Objects.ArrayDict;
  696. BEGIN
  697. Init^;
  698. defaultValue := NIL;
  699. type := CData;
  700. NEW(arrDict); allowedValues := arrDict;
  701. required := FALSE;
  702. END Init;
  703. PROCEDURE GetDefaultValue*(): String;
  704. BEGIN
  705. RETURN defaultValue
  706. END GetDefaultValue;
  707. PROCEDURE SetDefaultValue*(CONST defaultValue: ARRAY OF CHAR);
  708. BEGIN
  709. SELF.defaultValue := NewString(defaultValue)
  710. END SetDefaultValue;
  711. PROCEDURE GetType*(): SHORTINT;
  712. BEGIN
  713. RETURN type
  714. END GetType;
  715. PROCEDURE SetType*(type: SHORTINT);
  716. BEGIN
  717. SELF.type := type
  718. END SetType;
  719. (** Collection of NameContents *)
  720. PROCEDURE GetAllowedValues*(): Objects.Enumerator;
  721. BEGIN
  722. RETURN allowedValues.GetEnumerator()
  723. END GetAllowedValues;
  724. PROCEDURE AddAllowedValue*(CONST value: ARRAY OF CHAR);
  725. VAR nameContent: NameContent;
  726. BEGIN
  727. NEW(nameContent); nameContent.SetName(value);
  728. allowedValues.Add(value, nameContent)
  729. END AddAllowedValue;
  730. PROCEDURE IsRequired*(): BOOLEAN;
  731. BEGIN
  732. RETURN required
  733. END IsRequired;
  734. PROCEDURE SetRequired*(required: BOOLEAN);
  735. BEGIN
  736. SELF.required := required
  737. END SetRequired;
  738. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  739. VAR e: Objects.Enumerator; p: ANY;
  740. BEGIN
  741. w.String(name^); w.Char(Space);
  742. CASE type OF
  743. | CData: w.String("CDATA")
  744. | Id: w.String("ID")
  745. | IdRef: w.String("IDREF")
  746. | IdRefs: w.String("IDREFS")
  747. | Entity: w.String("ENTITY")
  748. | Entities: w.String("ENTITIES")
  749. | NmToken: w.String("NMTOKEN")
  750. | NmTokens: w.String("NMTOKENS")
  751. | Notation: w.String("NOTATION")
  752. | Enumeration:
  753. END;
  754. IF type # Enumeration THEN w.Char(Space) END;
  755. IF (type = Notation) OR (type = Enumeration) THEN
  756. w.Char('('); e := GetAllowedValues();
  757. p := e.GetNext(); p(Content).Write(w, context, level + 1);
  758. WHILE e.HasMoreElements() DO
  759. w.Char('|'); p := e.GetNext(); p(Content).Write(w, context, level + 1)
  760. END;
  761. w.String(") ")
  762. END;
  763. IF required THEN
  764. IF defaultValue = NIL THEN w.String('#REQUIRED')
  765. ELSE w.String('#FIXED "'); w.String(defaultValue^); w.String('"')
  766. END
  767. ELSE
  768. IF defaultValue = NIL THEN w.String('#IMPLIED')
  769. ELSE w.String('"'); w.String(defaultValue^); w.String('"')
  770. END
  771. END;
  772. NewLine(w, level)
  773. END Write;
  774. END AttributeDecl;
  775. TYPE
  776. CharReference* = OBJECT (Content)
  777. VAR
  778. code: LONGINT;
  779. PROCEDURE &Init*;
  780. BEGIN
  781. Init^;
  782. code := 0;
  783. END Init;
  784. PROCEDURE SetCode*(code: LONGINT);
  785. BEGIN
  786. SELF.code := code
  787. END SetCode;
  788. PROCEDURE GetCode*(): LONGINT;
  789. BEGIN
  790. RETURN code
  791. END GetCode;
  792. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  793. VAR codeArray: ARRAY 16 OF CHAR; codeStr: String;
  794. BEGIN
  795. DynamicStrings.IntToStr(code, codeArray);
  796. codeStr := NewString(codeArray);
  797. w.String('&#'); w.String(codeStr^); w.Char(';')
  798. END Write;
  799. END CharReference;
  800. TYPE
  801. EntityRef* = OBJECT (NameContent)
  802. VAR
  803. decl: EntityDecl;
  804. PROCEDURE &Init*;
  805. BEGIN
  806. Init^;
  807. decl := NIL;
  808. END Init;
  809. PROCEDURE GetEntityDecl*(): EntityDecl;
  810. BEGIN
  811. RETURN decl
  812. END GetEntityDecl;
  813. PROCEDURE SetDocument(document: Document);
  814. VAR dtd: DocTypeDecl;
  815. BEGIN
  816. dtd := document.GetDocTypeDecl();
  817. IF dtd # NIL THEN
  818. decl := dtd.GetEntityDecl(name^, GeneralEntity)
  819. END
  820. END SetDocument;
  821. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  822. BEGIN
  823. w.Char('&'); w.String(name^); w.Char(';')
  824. END Write;
  825. END EntityRef;
  826. TYPE
  827. InternalEntityRef* = OBJECT (EntityRef)
  828. PROCEDURE GetValue*(): String;
  829. BEGIN
  830. IF decl # NIL THEN RETURN decl.value
  831. ELSE RETURN NIL
  832. END
  833. END GetValue;
  834. END InternalEntityRef;
  835. TYPE
  836. ExternalEntityRef* = OBJECT (EntityRef)
  837. VAR
  838. coll: Objects.Collection;
  839. textDecl: TextDecl;
  840. PROCEDURE &Init*;
  841. BEGIN
  842. Init^;
  843. coll := NIL;
  844. textDecl := NIL;
  845. END Init;
  846. PROCEDURE GetTextDecl*(): TextDecl;
  847. BEGIN
  848. RETURN textDecl
  849. END GetTextDecl;
  850. PROCEDURE GetContents*(): Objects.Enumerator;
  851. BEGIN
  852. IF IsParsed() THEN RETURN coll.GetEnumerator()
  853. ELSE RETURN NIL
  854. END
  855. END GetContents;
  856. PROCEDURE AddContent*(c: Content);
  857. VAR arrColl: Objects.ArrayCollection;
  858. BEGIN
  859. IF coll = NIL THEN NEW(arrColl); coll := arrColl END;
  860. IF c IS TextDecl THEN
  861. textDecl := c(TextDecl)
  862. END;
  863. coll.Add(c)
  864. END AddContent;
  865. PROCEDURE IsParsed*(): BOOLEAN;
  866. BEGIN
  867. RETURN coll # NIL
  868. END IsParsed;
  869. PROCEDURE GetIdElement(CONST name, id: ARRAY OF CHAR): Element;
  870. VAR contents: Objects.Enumerator; p: ANY; retElement: Element;
  871. BEGIN
  872. retElement := NIL;
  873. IF IsParsed() THEN
  874. contents := GetContents();
  875. WHILE contents.HasMoreElements() & (retElement = NIL) DO
  876. p := contents.GetNext();
  877. IF p IS Element THEN
  878. retElement := p(Element).GetIdElement(name, id)
  879. ELSIF p IS ExternalEntityRef THEN
  880. retElement := p(ExternalEntityRef).GetIdElement(name, id)
  881. END
  882. END
  883. END;
  884. RETURN retElement
  885. END GetIdElement;
  886. END ExternalEntityRef;
  887. TYPE
  888. Chars* = OBJECT (Content)
  889. PROCEDURE GetStr*(): String;
  890. BEGIN
  891. RETURN NIL
  892. END GetStr;
  893. PROCEDURE GetLength*(): LONGINT;
  894. BEGIN
  895. RETURN 0
  896. END GetLength;
  897. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  898. VAR s: String;
  899. BEGIN
  900. s := GetStr(); w.String(s^)
  901. END Write;
  902. END Chars;
  903. TYPE
  904. ArrayChars* = OBJECT (Chars)
  905. VAR
  906. str: String;
  907. len: LONGINT;
  908. PROCEDURE &Init*;
  909. BEGIN
  910. str := NIL;
  911. len := 0;
  912. END Init;
  913. PROCEDURE GetStr*(): String;
  914. BEGIN
  915. RETURN str
  916. END GetStr;
  917. PROCEDURE GetLength*(): LONGINT;
  918. BEGIN
  919. RETURN len
  920. END GetLength;
  921. PROCEDURE SetStr*(CONST str: ARRAY OF CHAR);
  922. BEGIN
  923. SELF.str := NewString(str);
  924. len := DynamicStrings.StringLength(str)
  925. END SetStr;
  926. PROCEDURE SetStrAsString*(str : String);
  927. BEGIN
  928. SELF.str := str;
  929. len := DynamicStrings.StringLength(str^)
  930. END SetStrAsString;
  931. END ArrayChars;
  932. Comment* = OBJECT (ArrayChars)
  933. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  934. BEGIN
  935. NewLine(w, level-1); w.String("<!--"); Write^(w, context, level); w.String("-->"); NewLine(w, level)
  936. END Write;
  937. END Comment;
  938. TYPE
  939. CDataSect* = OBJECT (ArrayChars)
  940. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  941. VAR s : String; i, j : LONGINT; buf : ARRAY 4 OF CHAR;
  942. BEGIN
  943. w.String("<![CDATA[");
  944. s := GetStr(); COPY(" ", buf);
  945. IF (LEN(s^) < 3) THEN
  946. w.String(s^);
  947. ELSE
  948. buf[1] := s^[0];
  949. buf[2] := s^[1]; i := 2;
  950. WHILE (i < LEN(s^)) DO
  951. buf[0] := buf[1];
  952. buf[1] := buf[2];
  953. buf[2] := s^[i];
  954. INC(i);
  955. IF (buf = "]]>") THEN
  956. w.String("]]]]><![CDATA[>");
  957. IF ((i+2) < LEN(s^)) THEN
  958. buf[1] := s^[i]; INC(i);
  959. buf[2] := s^[i]; INC(i);
  960. ELSE
  961. j := 0;
  962. WHILE (i < LEN(s^)) DO
  963. buf[j] := s^[i]; INC(i); INC(j);
  964. END;
  965. buf[j] := 0X;
  966. END;
  967. ELSIF (i < LEN(s^)) THEN w.Char(buf[0]); END;
  968. END;
  969. w.String(buf);
  970. END;
  971. w.String("]]>"); NewLine(w, level)
  972. END Write;
  973. END CDataSect;
  974. TYPE
  975. ProcessingInstruction* = OBJECT (Content)
  976. VAR
  977. target, instruction: String;
  978. PROCEDURE &Init*;
  979. BEGIN
  980. Init^;
  981. target := NIL; instruction := NIL;
  982. END Init;
  983. PROCEDURE GetTarget*(): String;
  984. BEGIN
  985. RETURN target
  986. END GetTarget;
  987. PROCEDURE SetTarget*(CONST target: ARRAY OF CHAR);
  988. BEGIN
  989. SELF.target := NewString(target)
  990. END SetTarget;
  991. PROCEDURE GetInstruction*(): String;
  992. BEGIN
  993. RETURN instruction
  994. END GetInstruction;
  995. PROCEDURE SetInstruction*(CONST instruction: ARRAY OF CHAR);
  996. BEGIN
  997. SELF.instruction := NewString(instruction)
  998. END SetInstruction;
  999. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  1000. BEGIN
  1001. w.String("<?"); w.String(target^); w.Char(Space);
  1002. w.String(instruction^); w.String("?>"); NewLine(w, level)
  1003. END Write;
  1004. END ProcessingInstruction;
  1005. TYPE
  1006. Attribute* = OBJECT (NameContent)
  1007. VAR
  1008. value, elementName: String;
  1009. document: Document;
  1010. decl: AttributeDecl;
  1011. PROCEDURE &Init*;
  1012. BEGIN
  1013. Init^;
  1014. value := NIL; elementName := NIL;
  1015. document := NIL;
  1016. decl := NIL;
  1017. END Init;
  1018. PROCEDURE SetDocument(document: Document; elementName: String);
  1019. VAR dtd: DocTypeDecl; elementDecl: ElementDecl;
  1020. BEGIN
  1021. SELF.document := document;
  1022. SELF.elementName := elementName;
  1023. dtd := document.GetDocTypeDecl();
  1024. IF dtd # NIL THEN
  1025. elementDecl := dtd.GetElementDecl(elementName^);
  1026. IF elementDecl # NIL THEN
  1027. decl := elementDecl.GetAttributeDecl(name^);
  1028. IF (decl # NIL) & ((value = NIL) OR ~IsAllowedValue(value^)) THEN
  1029. value := decl.defaultValue
  1030. END
  1031. END
  1032. END
  1033. END SetDocument;
  1034. PROCEDURE IsAllowedValue*(CONST value: ARRAY OF CHAR): BOOLEAN;
  1035. BEGIN
  1036. IF decl = NIL THEN
  1037. RETURN TRUE
  1038. ELSE
  1039. CASE decl.GetType() OF
  1040. | CData: RETURN TRUE
  1041. | Id: RETURN document.root.GetIdElement(elementName^, value) = NIL
  1042. | IdRef: RETURN TRUE
  1043. | IdRefs: RETURN TRUE
  1044. | Entity: RETURN TRUE
  1045. | Entities: RETURN TRUE
  1046. | NmToken: RETURN TRUE
  1047. | NmTokens: RETURN TRUE
  1048. | Notation:
  1049. RETURN decl.allowedValues.Get(value) # NIL
  1050. | Enumeration:
  1051. RETURN decl.allowedValues.Get(value) # NIL
  1052. ELSE
  1053. END
  1054. END
  1055. END IsAllowedValue;
  1056. PROCEDURE GetValue*(): String;
  1057. BEGIN
  1058. RETURN value
  1059. END GetValue;
  1060. PROCEDURE SetValue*(CONST value: ARRAY OF CHAR);
  1061. BEGIN
  1062. IF IsAllowedValue(value) THEN
  1063. SELF.value := NewString(value)
  1064. END
  1065. END SetValue;
  1066. PROCEDURE SetValueAsString*(value : String);
  1067. BEGIN
  1068. ASSERT(value # NIL);
  1069. IF IsAllowedValue(value^) THEN
  1070. SELF.value := value;
  1071. END;
  1072. END SetValueAsString;
  1073. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  1074. BEGIN
  1075. IF value = NIL THEN KernelLog.String("NIL attribute "); KernelLog.Ln; RETURN END;
  1076. w.Char(Space); w.String(name^);
  1077. IF Strings.ContainsChar(value^, '"', FALSE) THEN
  1078. w.String("='"); w.String(value^); w.Char("'")
  1079. ELSE
  1080. w.String('="'); w.String(value^); w.Char('"')
  1081. END;
  1082. END Write;
  1083. END Attribute;
  1084. TraverseProc* = PROCEDURE {DELEGATE} (c: Content; data: ANY);
  1085. TYPE
  1086. Element* = OBJECT (Container)
  1087. VAR
  1088. root, parent : Element;
  1089. name: String; (* { name # NIL } *)
  1090. document: Document;
  1091. attributes : Attribute;
  1092. idAttribute: Attribute;
  1093. PROCEDURE &Init*;
  1094. BEGIN
  1095. Init^;
  1096. root := NIL; parent := NIL;
  1097. name := StrNoName;
  1098. document := NIL; attributes := NIL;
  1099. idAttribute := NIL;
  1100. END Init;
  1101. PROCEDURE AddContent*(content: Content);
  1102. BEGIN
  1103. ASSERT(content # NIL);
  1104. AddContent^(content);
  1105. IF (content IS Element) THEN
  1106. WITH content: Element DO
  1107. IF root # NIL THEN content.root := root ELSE content.root := SELF; END;
  1108. content.parent := SELF;
  1109. END;
  1110. END;
  1111. END AddContent;
  1112. PROCEDURE RemoveContent*(content : Content);
  1113. BEGIN
  1114. (*ASSERT(content # NIL);*)
  1115. IF content=NIL THEN RETURN END; (*PH 12/13: removing nothing is logically correct *)
  1116. RemoveContent^(content);
  1117. IF (content IS Element) THEN
  1118. IF (content(Element).parent = SELF) THEN
  1119. content(Element).parent := NIL;
  1120. content(Element).root := NIL;
  1121. END;
  1122. END;
  1123. END RemoveContent;
  1124. PROCEDURE SetDocument(document: Document);
  1125. VAR
  1126. dtd: DocTypeDecl; elementDecl: ElementDecl;
  1127. enum : Objects.Enumerator; c : Content; p: ANY; attribute: Attribute;
  1128. BEGIN
  1129. ASSERT(document # NIL);
  1130. SELF.document := document;
  1131. root := document.GetRoot();
  1132. dtd := document.GetDocTypeDecl();
  1133. IF dtd # NIL THEN
  1134. elementDecl := dtd.GetElementDecl(name^);
  1135. IF elementDecl # NIL THEN
  1136. enum := elementDecl.GetAttributeDecls();
  1137. WHILE enum.HasMoreElements() DO
  1138. p := enum.GetNext();
  1139. WITH p: AttributeDecl DO
  1140. attribute := GetAttribute(p.name^);
  1141. IF attribute # NIL THEN
  1142. attribute.SetDocument(document, name);
  1143. ELSE
  1144. NEW(attribute);
  1145. attribute.name := p.name;
  1146. attribute.value := p.defaultValue;
  1147. attribute.SetDocument(document, name);
  1148. AddAttribute(attribute);
  1149. END;
  1150. IF p.type = Id THEN idAttribute := attribute END
  1151. END
  1152. END
  1153. END
  1154. END;
  1155. c := GetFirst();
  1156. WHILE (c # NIL) DO
  1157. IF (c IS Element) THEN c(Element).SetDocument(document);
  1158. ELSIF (c IS EntityRef) THEN c(EntityRef).SetDocument(document);
  1159. END;
  1160. c := GetNext(c);
  1161. END;
  1162. END SetDocument;
  1163. PROCEDURE SetName*(CONST name: ARRAY OF CHAR);
  1164. BEGIN
  1165. SELF.name := NewString(name)
  1166. END SetName;
  1167. PROCEDURE SetNameAsString*(name : String);
  1168. BEGIN
  1169. ASSERT(name # NIL);
  1170. SELF.name := name
  1171. END SetNameAsString;
  1172. PROCEDURE GetName*(): String;
  1173. BEGIN
  1174. ASSERT(name # NIL);
  1175. RETURN name
  1176. END GetName;
  1177. PROCEDURE GetId*(): String;
  1178. BEGIN
  1179. IF idAttribute # NIL THEN RETURN idAttribute.value
  1180. ELSE RETURN NIL
  1181. END
  1182. END GetId;
  1183. PROCEDURE GetIdElement*(CONST name, id: ARRAY OF CHAR): Element;
  1184. VAR contents: Objects.Enumerator; content: ANY; idString: String; retElement: Element;
  1185. BEGIN
  1186. retElement := NIL;
  1187. IF SELF.name^ = name THEN
  1188. idString := GetId();
  1189. IF (idString # NIL) & (idString^ = id) THEN retElement := SELF END
  1190. END;
  1191. IF retElement = NIL THEN
  1192. contents := GetContents();
  1193. WHILE contents.HasMoreElements() & (retElement = NIL) DO
  1194. content := contents.GetNext();
  1195. IF content IS Element THEN
  1196. retElement := content(Element).GetIdElement(name, id)
  1197. ELSIF content IS ExternalEntityRef THEN
  1198. retElement := content(ExternalEntityRef).GetIdElement(name, id)
  1199. END
  1200. END
  1201. END;
  1202. RETURN retElement
  1203. END GetIdElement;
  1204. PROCEDURE AddAttribute*(attribute : Attribute);
  1205. VAR a : Attribute;
  1206. BEGIN {EXCLUSIVE}
  1207. ASSERT((attribute # NIL) & (attribute.next = NIL) & (attribute.name # NIL) & (attribute.name^ # ""));
  1208. RemoveAttributeInternal(attribute.name^);
  1209. IF (attributes = NIL) THEN
  1210. attributes := attribute;
  1211. ELSE
  1212. a := attributes;
  1213. WHILE (a.next # NIL) DO a := a.next (Attribute); END;
  1214. a.next := attribute;
  1215. END;
  1216. END AddAttribute;
  1217. PROCEDURE RemoveAttributeInternal(CONST name : ARRAY OF CHAR);
  1218. VAR a : Attribute;
  1219. BEGIN (* caller holds object lock *)
  1220. IF (attributes # NIL) THEN
  1221. IF (attributes.name^ = name) THEN
  1222. IF (attributes.next = NIL) THEN attributes := NIL; ELSE attributes := attributes.next (Attribute); END;
  1223. ELSE
  1224. a := attributes;
  1225. WHILE (a.next # NIL) & (a.next(Attribute).name^ # name) DO a := a.next (Attribute); END;
  1226. IF (a.next # NIL) THEN
  1227. a.next := a.next.next;
  1228. END;
  1229. END;
  1230. END;
  1231. END RemoveAttributeInternal;
  1232. PROCEDURE RemoveAttribute*(CONST name: ARRAY OF CHAR);
  1233. BEGIN {EXCLUSIVE}
  1234. RemoveAttributeInternal(name);
  1235. END RemoveAttribute;
  1236. PROCEDURE SetAttributeValue*(CONST name, value: ARRAY OF CHAR);
  1237. VAR attribute: Attribute;
  1238. BEGIN
  1239. NEW(attribute); attribute.SetName(name); attribute.SetValue(value); AddAttribute(attribute)
  1240. END SetAttributeValue;
  1241. PROCEDURE GetAttribute*(CONST name: ARRAY OF CHAR): Attribute;
  1242. VAR a : Attribute;
  1243. BEGIN {EXCLUSIVE}
  1244. a := attributes;
  1245. WHILE (a # NIL) & (a.name^ # name) DO
  1246. IF (a.next = NIL) THEN a := NIL; ELSE a := a.next (Attribute); END;
  1247. END;
  1248. RETURN a;
  1249. END GetAttribute;
  1250. PROCEDURE GetAttributeValue*(CONST name: ARRAY OF CHAR): String;
  1251. VAR a : Attribute;
  1252. BEGIN
  1253. a := GetAttribute(name);
  1254. IF (a # NIL) THEN
  1255. RETURN a.GetValue();
  1256. ELSE
  1257. RETURN NIL;
  1258. END;
  1259. END GetAttributeValue;
  1260. PROCEDURE GetAttributes*(): Objects.Enumerator;
  1261. VAR a : Attribute; array : Objects.PTRArray; enumerator : Objects.ArrayEnumerator; i, nofAttributes : LONGINT;
  1262. BEGIN {EXCLUSIVE}
  1263. nofAttributes := 0;
  1264. a := attributes;
  1265. WHILE (a # NIL) DO
  1266. INC(nofAttributes);
  1267. IF (a.next # NIL) THEN a := a.next (Attribute); ELSE a := NIL; END;
  1268. END;
  1269. NEW(array, nofAttributes);
  1270. a := attributes; i := 0;
  1271. WHILE (a # NIL) DO
  1272. array[i] := a; INC(i);
  1273. IF (a.next # NIL) THEN a := a.next (Attribute); ELSE a := NIL; END;
  1274. END;
  1275. NEW(enumerator, array);
  1276. RETURN enumerator;
  1277. END GetAttributes;
  1278. PROCEDURE HasAttribute*(CONST name : ARRAY OF CHAR) : BOOLEAN;
  1279. BEGIN
  1280. RETURN GetAttribute(name) # NIL;
  1281. END HasAttribute;
  1282. PROCEDURE GetRoot*(): Element;
  1283. BEGIN
  1284. RETURN root
  1285. END GetRoot;
  1286. PROCEDURE GetParent*(): Element;
  1287. BEGIN
  1288. RETURN parent
  1289. END GetParent;
  1290. PROCEDURE GetFirstChild*() : Element;
  1291. VAR c : Content;
  1292. BEGIN
  1293. c := GetFirst();
  1294. WHILE (c # NIL) & ~(c IS Element) DO
  1295. c := GetNext(c);
  1296. END;
  1297. IF (c # NIL) THEN
  1298. RETURN c(Element);
  1299. ELSE
  1300. RETURN NIL;
  1301. END;
  1302. END GetFirstChild;
  1303. PROCEDURE GetNextSibling*(): Element;
  1304. VAR c : Content;
  1305. BEGIN
  1306. c := next;
  1307. WHILE (c # NIL) & ~(c IS Element) DO c := c.next; END;
  1308. IF (c # NIL) THEN
  1309. RETURN c(Element);
  1310. ELSE
  1311. RETURN NIL;
  1312. END;
  1313. END GetNextSibling;
  1314. PROCEDURE GetPreviousSibling*() : Element;
  1315. VAR c : Content;
  1316. BEGIN
  1317. c := previous;
  1318. WHILE (c # NIL) & ~(c IS Element) DO c := c.previous; END;
  1319. IF (c # NIL) THEN
  1320. RETURN c(Element);
  1321. ELSE
  1322. RETURN NIL;
  1323. END;
  1324. END GetPreviousSibling;
  1325. PROCEDURE Traverse*(traverseProc: TraverseProc; data: ANY);
  1326. VAR c : Content;
  1327. BEGIN
  1328. ASSERT(traverseProc # NIL);
  1329. traverseProc(SELF, data);
  1330. c := GetFirst();
  1331. WHILE (c # NIL) DO
  1332. IF (c IS Element) THEN c(Element).Traverse(traverseProc, data);
  1333. ELSE traverseProc(c, data);
  1334. END;
  1335. c := GetNext(c);
  1336. END;
  1337. END Traverse;
  1338. PROCEDURE WriteAttributes*(w: Streams.Writer; context: ANY; level : LONGINT);
  1339. VAR a : Attribute;
  1340. BEGIN {EXCLUSIVE}
  1341. a := attributes;
  1342. WHILE (a # NIL) DO
  1343. a.Write(w, context, level + 1);
  1344. IF (a.next # NIL) THEN
  1345. a := a.next (Attribute);
  1346. ELSE
  1347. a := NIL;
  1348. END;
  1349. END;
  1350. END WriteAttributes;
  1351. PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
  1352. VAR c : Content;
  1353. BEGIN
  1354. w.Char('<'); w.String(name^);
  1355. WriteAttributes(w, context, level);
  1356. c := GetFirst();
  1357. IF (c = NIL) THEN w.String("/>")
  1358. ELSE
  1359. w.Char('>');
  1360. IF ~(c IS ArrayChars) THEN NewLine(w, level + 1) END;
  1361. c.Write(w, context, level + 1);
  1362. WHILE (GetNext(c) # NIL) DO c := GetNext(c); NewLine(w, level + 1); c.Write(w, context, level + 1); END;
  1363. IF ~(c IS ArrayChars) THEN NewLine(w, level); END;
  1364. w.String("</"); w.String(name^); w.Char('>');
  1365. END;
  1366. END Write;
  1367. END Element;
  1368. TYPE
  1369. GeneratorProcedure* = PROCEDURE(): Element;
  1370. ElementEntry* = OBJECT
  1371. VAR
  1372. name- : ARRAY 32 OF CHAR;
  1373. generator-: GeneratorProcedure;
  1374. generatorModule-, generatorProcedure- : Modules.Name;
  1375. PROCEDURE &Init*;
  1376. BEGIN
  1377. generator := NIL;
  1378. COPY("", generatorModule); COPY("", generatorProcedure);
  1379. END Init;
  1380. END ElementEntry;
  1381. ElementArray* = POINTER TO ARRAY OF ElementEntry;
  1382. TYPE
  1383. ElementRegistry* = OBJECT
  1384. VAR
  1385. generators: Objects.Dictionary;
  1386. timestamp : LONGINT;
  1387. PROCEDURE &Init*;
  1388. VAR arrDict: Objects.ArrayDict;
  1389. BEGIN
  1390. NEW(arrDict); generators := arrDict;
  1391. timestamp := 0;
  1392. END Init;
  1393. PROCEDURE RegisterElement*(CONST name: ARRAY OF CHAR; generator: GeneratorProcedure);
  1394. VAR e: ElementEntry; p: ANY;
  1395. BEGIN
  1396. ASSERT(generator # NIL);
  1397. p := generators.Get(name);
  1398. IF p = NIL THEN
  1399. NEW(e); COPY(name, e.name); e.generator := generator; generators.Add(name, e)
  1400. ELSE (* redefinition *)
  1401. p(ElementEntry).generator := generator
  1402. END;
  1403. INC(timestamp);
  1404. END RegisterElement;
  1405. PROCEDURE RegisterElementByName*(CONST name: ARRAY OF CHAR; CONST generatorModule, generatorProcedure: Modules.Name);
  1406. VAR e: ElementEntry; p: ANY;
  1407. BEGIN
  1408. ASSERT((generatorModule # "") & (generatorProcedure # ""));
  1409. p := generators.Get(name);
  1410. IF p = NIL THEN
  1411. NEW(e);
  1412. COPY(name, e.name);
  1413. e.generatorModule := generatorModule;
  1414. e.generatorProcedure := generatorProcedure;
  1415. generators.Add(name, e)
  1416. ELSE (* redefinition *)
  1417. p(ElementEntry).generatorModule := generatorModule;
  1418. p(ElementEntry).generatorProcedure := generatorProcedure;
  1419. END;
  1420. INC(timestamp);
  1421. END RegisterElementByName;
  1422. PROCEDURE UnregisterElement*(CONST name: ARRAY OF CHAR);
  1423. BEGIN
  1424. generators.Remove(name);
  1425. INC(timestamp);
  1426. END UnregisterElement;
  1427. PROCEDURE InstantiateElement*(CONST name: ARRAY OF CHAR): Element;
  1428. VAR element : Element; entry : ElementEntry; p: ANY; generator : GeneratorProcedure;
  1429. BEGIN
  1430. element := NIL;
  1431. p := generators.Get(name);
  1432. IF (p # NIL) THEN entry := p (ElementEntry); END;
  1433. IF (entry # NIL) THEN
  1434. IF entry.generator # NIL THEN
  1435. element := entry.generator();
  1436. ELSE
  1437. GETPROCEDURE(entry.generatorModule, entry.generatorProcedure, generator);
  1438. IF (generator # NIL) THEN
  1439. element := generator();
  1440. ELSE
  1441. KernelLog.String("Warning: XML.ElementRegistry.InstantiateElement: Factory procedure ");
  1442. KernelLog.String(entry.generatorModule); KernelLog.String("."); KernelLog.String(entry.generatorProcedure);
  1443. KernelLog.String(" not found."); KernelLog.Ln;
  1444. END
  1445. END
  1446. END;
  1447. RETURN element;
  1448. END InstantiateElement;
  1449. (** fof, late time instantiation to be able to react on generator properties *)
  1450. PROCEDURE InstantiateLate*(e: Element): Element;
  1451. BEGIN
  1452. RETURN e (* stub *)
  1453. END InstantiateLate;
  1454. PROCEDURE GetTimestamp*() : LONGINT;
  1455. BEGIN
  1456. RETURN timestamp;
  1457. END GetTimestamp;
  1458. PROCEDURE GetElements*() : ElementArray;
  1459. VAR enumerator : Objects.Enumerator; nofElements, i : LONGINT; ptr : ANY; ea : ElementArray;
  1460. BEGIN
  1461. enumerator := generators.GetEnumerator();
  1462. nofElements := 0;
  1463. WHILE enumerator.HasMoreElements() DO INC(nofElements); ptr := enumerator.GetNext(); END;
  1464. IF (nofElements = 0) THEN
  1465. ea := NIL;
  1466. ELSE
  1467. NEW(ea, nofElements);
  1468. enumerator.Reset;
  1469. i := 0;
  1470. WHILE (i < nofElements) & enumerator.HasMoreElements() DO
  1471. ptr := enumerator.GetNext();
  1472. IF (ptr # NIL) & (ptr IS ElementEntry) THEN
  1473. ea[i] := ptr (ElementEntry);
  1474. ELSE
  1475. ea[i] := NIL;
  1476. END;
  1477. INC(i);
  1478. END;
  1479. END;
  1480. RETURN ea;
  1481. END GetElements;
  1482. END ElementRegistry;
  1483. VAR
  1484. StrNoName : Strings.String;
  1485. (** Write an 0X-terminated UTF8 string to a stream (excl. 0X). XML special characters are escaped.
  1486. Also works for ASCII strings. *)
  1487. PROCEDURE UTF8ToStream*(CONST string : ARRAY OF CHAR; w : Streams.Writer; VAR res : WORD);
  1488. VAR codeLength, stringLength, i : LONGINT; ch : CHAR;
  1489. BEGIN
  1490. ASSERT(w # NIL);
  1491. res := Ok;
  1492. stringLength := LEN(string);
  1493. i := 0;
  1494. WHILE (res = Ok) & (i < stringLength) & (string[i] # 0X) DO
  1495. ch := string[i];
  1496. codeLength := ORD(UTF8Strings.CodeLength[ORD(ch)]);
  1497. IF (codeLength = 1) THEN
  1498. CASE ch OF
  1499. |'&': w.String("&amp;");
  1500. |'<': w.String("&lt;");
  1501. |'>': w.String("&gt;");
  1502. |'"': w.String("&quot;");
  1503. |"'": w.String("&apos;");
  1504. ELSE
  1505. w.Char(ch);
  1506. END;
  1507. ELSIF (codeLength > 0) & (i + codeLength <= stringLength) THEN
  1508. w.Bytes(string, i, codeLength);
  1509. ELSE
  1510. res := InvalidString;
  1511. END;
  1512. INC(i, codeLength);
  1513. END;
  1514. IF (i >= stringLength) OR (string[i] # 0X) THEN
  1515. res := InvalidString;
  1516. END;
  1517. END UTF8ToStream;
  1518. (** Read an UTF8 string from a stream and undo escaping of XML special characters. If the string array is to small, the string
  1519. will be truncated and an error will be reported. <string> is always a valid 0X-terminated string.
  1520. Also works for ASCII strings. *)
  1521. PROCEDURE UTF8FromStream*(VAR string : ARRAY OF CHAR; r : Streams.Reader; VAR res : WORD);
  1522. VAR ch : CHAR; escapeBuffer : ARRAY 8 OF CHAR; escaping : BOOLEAN; escapeIdx, codeLength, stringLength, i, len, actLen : LONGINT;
  1523. PROCEDURE FlushEscapeBuffer;
  1524. VAR j : LONGINT;
  1525. BEGIN
  1526. IF escaping THEN
  1527. j := 0;
  1528. WHILE (i < stringLength - 1) & (escapeBuffer[j] # 0X) DO
  1529. string[i] := escapeBuffer[j];
  1530. INC(i); INC(j);
  1531. END;
  1532. IF (escapeBuffer[j] # 0X) THEN res := BufferError; END;
  1533. escaping := FALSE;
  1534. END;
  1535. END FlushEscapeBuffer;
  1536. PROCEDURE CheckEscapeBuffer;
  1537. BEGIN
  1538. ASSERT(i < stringLength);
  1539. IF (escapeIdx = 4) THEN
  1540. IF (escapeBuffer = "&lt;") THEN string[i] := "<"; INC(i); escaping := FALSE;
  1541. ELSIF (escapeBuffer = "&gt;") THEN string[i] := ">"; INC(i); escaping := FALSE;
  1542. END;
  1543. ELSIF (escapeIdx = 5) & (escapeBuffer = "&amp;") THEN
  1544. string[i] := "&"; INC(i); escaping := FALSE;
  1545. ELSIF (escapeIdx = 6) THEN
  1546. IF (escapeBuffer = "&quot;") THEN string[i] := '"'; INC(i); escaping := FALSE;
  1547. ELSIF (escapeBuffer = "&apos;") THEN string[i] := "'"; INC(i); escaping := FALSE;
  1548. END;
  1549. ELSIF (escapeIdx > 6) THEN
  1550. FlushEscapeBuffer;
  1551. END;
  1552. END CheckEscapeBuffer;
  1553. BEGIN
  1554. ASSERT((r # NIL) & (LEN(string) >= 1));
  1555. res := Ok;
  1556. escaping := FALSE;
  1557. stringLength := LEN(string);
  1558. i := 0;
  1559. ch := r.Peek();
  1560. WHILE (res = Ok) & (ch # 0X) & (i < stringLength - 1) DO
  1561. codeLength := ORD(UTF8Strings.CodeLength[ORD(ch)]);
  1562. IF (codeLength = 1) THEN
  1563. ch := r.Get();
  1564. IF (ch = "&") THEN
  1565. FlushEscapeBuffer;
  1566. escaping := TRUE;
  1567. escapeBuffer[0] := ch;
  1568. escapeBuffer[1] := 0X;
  1569. escapeIdx := 1;
  1570. ELSIF escaping THEN
  1571. escapeBuffer[escapeIdx] := ch;
  1572. escapeBuffer[escapeIdx + 1] := 0X;
  1573. INC(escapeIdx);
  1574. CheckEscapeBuffer;
  1575. ELSE
  1576. string[i] := ch;
  1577. INC(i);
  1578. END;
  1579. ELSIF (codeLength > 0) THEN
  1580. FlushEscapeBuffer;
  1581. len := MIN(codeLength, stringLength - 1 - i);
  1582. IF (len > 0) THEN
  1583. r.Bytes(string, i, len, actLen);
  1584. IF (actLen # len) THEN
  1585. res := InvalidString;
  1586. ELSIF (len # codeLength) THEN
  1587. res := BufferError;
  1588. END;
  1589. INC(i, actLen);
  1590. ELSE
  1591. res := BufferError;
  1592. END;
  1593. ELSE
  1594. res := InvalidString;
  1595. END;
  1596. ch := r.Peek();
  1597. END;
  1598. string[i] := 0X;
  1599. END UTF8FromStream;
  1600. PROCEDURE NewLine(w : Streams.Writer; level : LONGINT);
  1601. BEGIN
  1602. w.Ln; WHILE level > 0 DO w.Char(Tab); DEC(level) END
  1603. END NewLine;
  1604. PROCEDURE NewString(CONST value: ARRAY OF CHAR): String;
  1605. VAR s: String;
  1606. BEGIN
  1607. NEW(s, DynamicStrings.StringLength(value) + 1);
  1608. COPY(value, s^);
  1609. RETURN s
  1610. END NewString;
  1611. BEGIN
  1612. StrNoName := Strings.NewString("");
  1613. END XML.