XMLParser.Mod 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. MODULE XMLParser; (** AUTHOR "swalthert"; PURPOSE "XML parser"; *)
  2. IMPORT
  3. Strings, KernelLog, DynamicStrings, Scanner := XMLScanner, XML;
  4. CONST
  5. Ok* = XML.Ok;
  6. UnknownError* = -1;
  7. TYPE
  8. String = Strings.String;
  9. Parser* = OBJECT
  10. VAR
  11. scanner: Scanner.Scanner;
  12. dtd: XML.DocTypeDecl;
  13. elemReg*: XML.ElementRegistry;
  14. reportError*: PROCEDURE {DELEGATE} (pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
  15. res*: LONGINT; (* result success / error code *)
  16. ds1, ds2 : DynamicStrings.DynamicString; (** utility string, { (ds1 # NIL) & (ds2 # NIL) } *)
  17. PROCEDURE &Init*(s: Scanner.Scanner);
  18. BEGIN
  19. reportError := DefaultReportError;
  20. scanner := s;
  21. res := Ok;
  22. NEW(ds1); NEW(ds2);
  23. END Init;
  24. PROCEDURE Error(CONST msg: ARRAY OF CHAR);
  25. BEGIN
  26. reportError(scanner.GetPos(), scanner.line, scanner.col, msg);
  27. res := UnknownError;
  28. END Error;
  29. PROCEDURE CheckSymbol(expectedSymbols: SET; CONST errormsg: ARRAY OF CHAR): BOOLEAN;
  30. BEGIN
  31. IF ~(scanner.sym IN expectedSymbols) THEN
  32. Error(errormsg); RETURN FALSE
  33. ELSE
  34. RETURN TRUE
  35. END
  36. END CheckSymbol;
  37. PROCEDURE ExpandCharacterRef(num: LONGINT): CHAR;
  38. BEGIN
  39. RETURN CHR(SHORT(SHORT(num)))
  40. END ExpandCharacterRef;
  41. PROCEDURE ExpandEntityRef(CONST name: ARRAY OF CHAR; type: SHORTINT): String;
  42. VAR generalEntity: XML.EntityDecl;
  43. BEGIN
  44. IF dtd # NIL THEN
  45. generalEntity := dtd.GetEntityDecl(name, type);
  46. IF generalEntity # NIL THEN
  47. RETURN generalEntity.GetValue()
  48. ELSE
  49. RETURN NIL;
  50. END
  51. ELSE
  52. RETURN NIL;
  53. END;
  54. END ExpandEntityRef;
  55. PROCEDURE Parse*(): XML.Document;
  56. VAR doc: XML.Document; e : XML.Element; s: String;
  57. BEGIN
  58. NEW(doc); doc.SetPos(scanner.GetPos()); dtd := doc.GetDocTypeDecl();
  59. scanner.ScanContent(); (* prolog *)
  60. IF scanner.sym = Scanner.TagXMLDeclOpen THEN (* XMLDecl? *)
  61. doc.AddContent(ParseXMLDecl());
  62. scanner.ScanContent()
  63. END;
  64. WHILE (scanner.sym # Scanner.TagDeclOpen) & (scanner.sym # Scanner.TagElemStartOpen) DO (* Misc* *)
  65. CASE scanner.sym OF
  66. | Scanner.TagPIOpen: doc.AddContent(ParseProcessingInstruction())
  67. | Scanner.Comment: doc.AddContent(ParseComment())
  68. ELSE
  69. Error("unknown XML content (Document Type Declaration, Processing Instruction, Comment or Root Element expected)");
  70. RETURN doc
  71. END;
  72. scanner.ScanContent()
  73. END;
  74. IF scanner.sym = Scanner.TagDeclOpen THEN (* (doctypedecl Misc* )? *)
  75. s := scanner.GetString(Scanner.Str_Other); (* doctypedecl .. *)
  76. IF s^ = 'DOCTYPE' THEN
  77. ParseDocTypeDecl(); doc.AddContent(dtd)
  78. ELSE
  79. Error("'<!DOCTYPE' expected"); RETURN doc
  80. END;
  81. scanner.ScanContent();
  82. WHILE (scanner.sym # Scanner.TagElemStartOpen) DO (* .. Misc* *)
  83. CASE scanner.sym OF
  84. | Scanner.TagPIOpen: doc.AddContent(ParseProcessingInstruction())
  85. | Scanner.Comment: doc.AddContent(ParseComment())
  86. | Scanner.TagElemStartOpen: (* do nothing *)
  87. ELSE Error("unknown XML content (Processing Instruction, Comment or Root Element expected)"); RETURN doc
  88. END;
  89. scanner.ScanContent()
  90. END
  91. END;
  92. e := ParseElement();
  93. IF e = NIL THEN RETURN NIL END;
  94. doc.AddContent(e); (* element *)
  95. scanner.ScanContent();
  96. WHILE scanner.sym # Scanner.Eof DO (* Misc* *)
  97. CASE scanner.sym OF
  98. | Scanner.TagPIOpen: doc.AddContent(ParseProcessingInstruction())
  99. | Scanner.Comment: doc.AddContent(ParseComment())
  100. | Scanner.Eof: (* do nothing *)
  101. ELSE Error("unknown XML content (Processing Instruction, Comment or End of file expected)"); RETURN doc
  102. END;
  103. scanner.ScanContent()
  104. END;
  105. RETURN doc
  106. END Parse;
  107. PROCEDURE ParseExtGenEntity*(extEntityRef: XML.ExternalEntityRef);
  108. BEGIN
  109. scanner.ScanContent();
  110. IF scanner.sym = Scanner.TagXMLDeclOpen THEN
  111. extEntityRef.AddContent(ParseTextDecl());
  112. scanner.ScanContent()
  113. END;
  114. REPEAT
  115. CASE scanner.sym OF
  116. | Scanner.CharData: extEntityRef.AddContent(ParseCharData())
  117. | Scanner.TagElemStartOpen: extEntityRef.AddContent(ParseElement())
  118. | Scanner.CharRef: extEntityRef.AddContent(ParseCharRef())
  119. | Scanner.EntityRef: extEntityRef.AddContent(ParseEntityRef())
  120. | Scanner.CDataSect: extEntityRef.AddContent(ParseCDataSect())
  121. | Scanner.Comment: extEntityRef.AddContent(ParseComment())
  122. | Scanner.TagPIOpen: extEntityRef.AddContent(ParseProcessingInstruction())
  123. | Scanner.TagElemEndOpen: (* do nothing *)
  124. | Scanner.Eof: Error("element not closed"); RETURN
  125. ELSE
  126. Error("unknown Element Content"); RETURN
  127. END;
  128. scanner.ScanContent()
  129. UNTIL scanner.sym = Scanner.Eof
  130. END ParseExtGenEntity;
  131. PROCEDURE ParseXMLDecl(): XML.XMLDecl;
  132. VAR decl: XML.XMLDecl; s: String;
  133. BEGIN
  134. NEW(decl); decl.SetPos(scanner.GetPos());
  135. scanner.ScanMarkup();
  136. IF ~CheckSymbol({Scanner.Name}, "'version' expected") THEN RETURN decl END;
  137. s := scanner.GetString(Scanner.Str_Other);
  138. IF s^ # "version" THEN Error("'version' expected"); RETURN decl END;
  139. scanner.ScanMarkup();
  140. IF ~CheckSymbol({Scanner.Equal}, "'=' expected") THEN RETURN decl END;
  141. scanner.ScanMarkup();
  142. IF ~CheckSymbol({Scanner.Literal}, "Version Number expected") THEN RETURN decl END;
  143. s := scanner.GetString(Scanner.Str_Other);
  144. decl.SetVersion(s^);
  145. scanner.ScanMarkup(); s := scanner.GetString(Scanner.Str_Other);
  146. IF (scanner.sym = Scanner.Name) & (s^ = "encoding") THEN
  147. scanner.ScanMarkup();
  148. IF ~CheckSymbol({Scanner.Equal}, "'=' expected") THEN RETURN decl END;
  149. scanner.ScanMarkup();
  150. IF ~CheckSymbol({Scanner.Literal}, "Encoding Name expected") THEN RETURN decl END;
  151. s := scanner.GetString(Scanner.Str_Other);
  152. decl.SetEncoding(s^);
  153. scanner.ScanMarkup(); s := scanner.GetString(Scanner.Str_Other)
  154. END;
  155. IF (scanner.sym = Scanner.Name) & (s^ = "standalone") THEN
  156. scanner.ScanMarkup();
  157. IF ~CheckSymbol({Scanner.Equal}, "'=' expected") THEN RETURN decl END;
  158. scanner.ScanMarkup();
  159. IF ~CheckSymbol({Scanner.Literal}, '"yes" or "no" expected') THEN RETURN decl END;
  160. s := scanner.GetString(Scanner.Str_Other);
  161. IF s^ = "yes" THEN decl.SetStandalone(TRUE)
  162. ELSIF s^ = "no" THEN decl.SetStandalone(FALSE)
  163. ELSE Error('"yes" or "no" expected'); RETURN decl
  164. END;
  165. scanner.ScanMarkup()
  166. END;
  167. IF ~CheckSymbol({Scanner.TagPIClose}, "'?>' expected") THEN RETURN decl END;
  168. RETURN decl
  169. END ParseXMLDecl;
  170. PROCEDURE ParseTextDecl(): XML.TextDecl;
  171. VAR decl: XML.TextDecl; s: String;
  172. BEGIN
  173. NEW(decl); decl.SetPos(scanner.GetPos());
  174. scanner.ScanMarkup();
  175. IF ~CheckSymbol({Scanner.Name}, "'version' expected") THEN RETURN decl END;
  176. s := scanner.GetString(Scanner.Str_Other);
  177. IF s^ # "version" THEN Error("'version' expected"); RETURN decl END;
  178. scanner.ScanMarkup();
  179. IF ~CheckSymbol({Scanner.Equal}, "'=' expected") THEN RETURN decl END;
  180. scanner.ScanMarkup();
  181. IF ~CheckSymbol({Scanner.Literal}, "Version Number expected") THEN RETURN decl END;
  182. s := scanner.GetString(Scanner.Str_Other);
  183. decl.SetVersion(s^);
  184. scanner.ScanMarkup(); s := scanner.GetString(Scanner.Str_Other);
  185. IF (scanner.sym = Scanner.Name) & (s^ = "encoding") THEN
  186. scanner.ScanMarkup();
  187. IF ~CheckSymbol({Scanner.Equal}, "'=' expected") THEN RETURN decl END;
  188. scanner.ScanMarkup();
  189. IF ~CheckSymbol({Scanner.Literal}, "Encoding Name expected") THEN RETURN decl END;
  190. s := scanner.GetString(Scanner.Str_Other);
  191. decl.SetEncoding(s^);
  192. scanner.ScanMarkup(); s := scanner.GetString(Scanner.Str_Other)
  193. END;
  194. IF ~CheckSymbol({Scanner.TagPIClose}, "'?>' expected") THEN RETURN decl END;
  195. RETURN decl
  196. END ParseTextDecl;
  197. PROCEDURE ParseComment(): XML.Comment;
  198. VAR comment: XML.Comment; s: String;
  199. BEGIN
  200. NEW(comment); comment.SetPos(scanner.GetPos());
  201. s := scanner.GetString(Scanner.Str_Comment);
  202. comment.SetStrAsString(s);
  203. RETURN comment
  204. END ParseComment;
  205. PROCEDURE ParseProcessingInstruction(): XML.ProcessingInstruction;
  206. VAR pi: XML.ProcessingInstruction; s: String;
  207. BEGIN
  208. NEW(pi); pi.SetPos(scanner.GetPos());
  209. s := scanner.GetString(Scanner.Str_ProcessingInstruction);
  210. pi.SetTarget(s^);
  211. scanner.ScanPInstruction();
  212. IF ~CheckSymbol({Scanner.TagPIClose}, "'?>' expected") THEN RETURN pi END;
  213. s := scanner.GetString(Scanner.Str_ProcessingInstruction);
  214. pi.SetInstruction(s^);
  215. RETURN pi
  216. END ParseProcessingInstruction;
  217. PROCEDURE ParseDocTypeDecl;
  218. VAR externalSubset: XML.EntityDecl; s: String;
  219. BEGIN
  220. NEW(dtd); dtd.SetPos(scanner.GetPos());
  221. scanner.ScanMarkup();
  222. IF ~CheckSymbol({Scanner.Name}, "DTD name expected") THEN RETURN END;
  223. s := scanner.GetString(Scanner.Str_Other); dtd.SetNameAsString(s);
  224. scanner.ScanMarkup();
  225. IF scanner.sym = Scanner.Name THEN (* DTD points to external subset *)
  226. NEW(externalSubset); externalSubset.SetPos(scanner.GetPos());
  227. s := scanner.GetString(Scanner.Str_Other);
  228. IF s^ = 'SYSTEM' THEN
  229. s := ParseSystemLiteral();
  230. externalSubset.SetSystemId(s^)
  231. ELSIF s^ = 'PUBLIC' THEN
  232. s := ParsePubidLiteral();
  233. externalSubset.SetPublicId(s^);
  234. s := ParseSystemLiteral();
  235. externalSubset.SetSystemId(s^)
  236. ELSE
  237. Error("'SYSTEM' or 'PUBLIC' expected"); RETURN
  238. END;
  239. dtd.SetExternalSubset(externalSubset);
  240. scanner.ScanMarkup()
  241. END;
  242. IF scanner.sym = Scanner.BracketOpen THEN (* markupdecl *)
  243. ParseMarkupDecls()
  244. END;
  245. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN END;
  246. END ParseDocTypeDecl;
  247. PROCEDURE ParseMarkupDecls;
  248. VAR s: String; (* oldscanner: Scanner.Scanner; *)
  249. BEGIN
  250. REPEAT
  251. scanner.ScanMarkup();
  252. CASE scanner.sym OF
  253. | Scanner.TagDeclOpen:
  254. s := scanner.GetString(Scanner.Str_Other);
  255. IF s^ = 'ELEMENT' THEN
  256. ParseElementDecl(dtd)
  257. ELSIF s^ = 'ATTLIST' THEN
  258. ParseAttListDecl(dtd)
  259. ELSIF s^ = 'ENTITY' THEN
  260. ParseEntityDecl(dtd)
  261. ELSIF s^ = 'NOTATION' THEN
  262. ParseNotationDecl(dtd)
  263. ELSE
  264. Error("'ELEMENT', 'ATTLIST' or 'NOTATION' expected"); RETURN
  265. END
  266. |Scanner.TagPIOpen: dtd.AddMarkupDecl(ParseProcessingInstruction())
  267. | Scanner.Comment: dtd.AddMarkupDecl(ParseComment())
  268. (* | Scanner.ParamEntityRef:
  269. s := scanner.GetStr();
  270. s := ExpandEntityRef(s^, XML.ParameterEntity);
  271. f := Files.New(""); Files.OpenWriter(w, f, 0); w.Bytes(s^, 0, LEN(s^) - 1); w.Update;
  272. oldscanner := scanner;
  273. NEW(scanner, f);
  274. ParseMarkupDecls();
  275. scanner := oldscanner *)
  276. | Scanner.BracketClose: (* end of markupdecl *)
  277. | Scanner.Eof, Scanner.Invalid: RETURN
  278. ELSE
  279. Error("unknown markup declaration"); RETURN
  280. END
  281. UNTIL scanner.sym = Scanner.BracketClose;
  282. scanner.ScanMarkup()
  283. END ParseMarkupDecls;
  284. (*
  285. elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>"
  286. contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
  287. S ::= (#x20 | #x9 | #xD | #xA)+
  288. *)
  289. PROCEDURE ParseElementDecl(dtd: XML.DocTypeDecl);
  290. VAR ed: XML.ElementDecl; ccp: XML.CollectionCP; s: String;
  291. contentType: SHORTINT;
  292. BEGIN
  293. scanner.ScanMarkup();
  294. IF ~CheckSymbol({Scanner.Name}, "Element name expected") THEN RETURN END;
  295. s := scanner.GetString(Scanner.Str_ElementName);
  296. ed := dtd.GetElementDecl(s^);
  297. IF ed = NIL THEN (* Attribute List Declaration not occured yet -> create new element declaration and add it to the DTD *)
  298. NEW(ed); ed.SetPos(scanner.GetPos());
  299. ed.SetNameAsString(s);
  300. dtd.AddMarkupDecl(ed)
  301. END;
  302. scanner.ScanMarkup();
  303. IF ~CheckSymbol({Scanner.Name, Scanner.ParenOpen}, "'EMPTY', 'ANY', Mixed or Element Content expected") THEN
  304. RETURN END;
  305. IF scanner.sym = Scanner.Name THEN
  306. s := scanner.GetString(Scanner.Str_Other);
  307. IF s^ = 'EMPTY' THEN
  308. ed.SetContentType(XML.Empty)
  309. ELSIF s^ = 'ANY' THEN
  310. ed.SetContentType(XML.Any)
  311. ELSE
  312. Error("'EMPTY' or 'ANY' expected"); RETURN
  313. END;
  314. scanner.ScanMarkup();
  315. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN END;
  316. ELSIF scanner.sym = Scanner.ParenOpen THEN (* Mixed or children element content *)
  317. ccp := ParseContentParticle(contentType);
  318. ed.SetContent(ccp);
  319. ed.SetContentType(contentType)
  320. END
  321. END ParseElementDecl;
  322. PROCEDURE ParseAttListDecl(dtd: XML.DocTypeDecl);
  323. VAR ed: XML.ElementDecl; ad: XML.AttributeDecl; s: String;
  324. BEGIN
  325. scanner.ScanMarkup(); (* parse element name *)
  326. IF ~CheckSymbol({Scanner.Name}, "Element name expected") THEN RETURN END;
  327. s := scanner.GetString(Scanner.Str_AttributeName);
  328. ed := dtd.GetElementDecl(s^);
  329. IF ed = NIL THEN (* Element Declaration not occured yet -> create new element declaration and add it to the DTD *)
  330. NEW(ed); ed.SetPos(scanner.GetPos());
  331. ed.SetNameAsString(s);
  332. dtd.AddMarkupDecl(ed)
  333. END;
  334. scanner.ScanMarkup();
  335. WHILE (scanner.sym # Scanner.TagClose) DO (* parse AttDefs *)
  336. IF ~CheckSymbol({Scanner.Name}, "Attribute Name expected") THEN RETURN END;
  337. s := scanner.GetString(Scanner.Str_AttributeName); NEW(ad); ad.SetPos(scanner.GetPos());
  338. ad.SetNameAsString(s);
  339. scanner.ScanMarkup();
  340. IF ~CheckSymbol({Scanner.Name, Scanner.ParenOpen}, "Attribute Type expected") THEN RETURN END;
  341. IF scanner.sym = Scanner.Name THEN
  342. s := scanner.GetString(Scanner.Str_Other);
  343. IF s^ = 'CDATA' THEN ad.SetType(XML.CData)
  344. ELSIF s^ = 'ID' THEN ad.SetType(XML.Id)
  345. ELSIF s^ = 'IDREF' THEN ad.SetType(XML.IdRef)
  346. ELSIF s^ = 'IDREFS' THEN ad.SetType(XML.IdRefs)
  347. ELSIF s^ = 'ENTITY' THEN ad.SetType(XML.Entity)
  348. ELSIF s^ = 'ENTITIES' THEN ad.SetType(XML.Entities)
  349. ELSIF s^ = 'NMTOKEN' THEN ad.SetType(XML.NmToken)
  350. ELSIF s^ = 'NMTOKENS' THEN ad.SetType(XML.NmTokens)
  351. ELSIF s^ = 'NOTATION' THEN
  352. ad.SetType(XML.Notation);
  353. scanner.ScanMarkup();
  354. IF ~CheckSymbol({Scanner.ParenOpen}, "'(' expected") THEN RETURN END;
  355. scanner.ScanMarkup();
  356. IF ~CheckSymbol({Scanner.Name}, "Notation Name expected") THEN RETURN END;
  357. scanner.ScanMarkup()
  358. ELSE Error("Attribute Type expected"); RETURN
  359. END
  360. ELSIF scanner.sym = Scanner.ParenOpen THEN
  361. ad.SetType(XML.Enumeration);
  362. scanner.ScanMarkup();
  363. IF ~CheckSymbol({Scanner.Name, Scanner.Nmtoken}, "Value Nmtoken expected") THEN RETURN END;
  364. END;
  365. IF (ad.GetType() = XML.Notation) OR (ad.GetType() = XML.Enumeration) THEN
  366. WHILE (scanner.sym = Scanner.Name) OR
  367. ((scanner.sym = Scanner.Nmtoken) & (ad.GetType() = XML.Enumeration)) DO
  368. s := scanner.GetString(Scanner.Str_Other);
  369. ad.AddAllowedValue(s^);
  370. scanner.ScanMarkup();
  371. IF scanner.sym = Scanner.Or THEN
  372. scanner.ScanMarkup()
  373. END
  374. END;
  375. IF ~CheckSymbol({Scanner.ParenClose}, "')' expected") THEN RETURN END;
  376. END;
  377. scanner.ScanMarkup();
  378. s := scanner.GetString(Scanner.Str_Other); (* parse DefaultDecl *)
  379. IF ~CheckSymbol({Scanner.PoundName, Scanner.Literal},
  380. "'#REQUIRED', '#IMPLIED', '#FIXED' or AttValue expected") THEN RETURN END;
  381. IF scanner.sym = Scanner.PoundName THEN
  382. IF (s^ = '#REQUIRED') THEN
  383. ad.SetRequired(TRUE)
  384. ELSIF (s^ = '#FIXED') THEN
  385. ad.SetRequired(TRUE);
  386. scanner.ScanMarkup();
  387. IF ~CheckSymbol({Scanner.Literal}, "AttValue expected") THEN RETURN END
  388. ELSIF (s^ = '#IMPLIED') THEN
  389. ad.SetRequired(FALSE)
  390. ELSE
  391. Error("'#REQUIRED', '#IMPLIED' or '#FIXED' expected"); RETURN
  392. END
  393. ELSIF scanner.sym = Scanner.Literal THEN
  394. ad.SetRequired(FALSE)
  395. END;
  396. IF (scanner.sym = Scanner.Literal) THEN
  397. s := ParseAttributeValue();
  398. ad.SetDefaultValue(s^)
  399. END;
  400. scanner.ScanMarkup();
  401. ed.AddAttributeDecl(ad);
  402. END;
  403. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN END;
  404. END ParseAttListDecl;
  405. (*
  406. Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
  407. | '(' S? '#PCDATA' S? ')'
  408. children ::= (choise | seq) ('?' | '*' | '+')?
  409. cp ::= (Name | choise | seq) ('?' | '*' | '+')?
  410. choice ::= '(' S? cp (S? '|' S? cp)+ S? ')'
  411. seq ::= '(' S? cp (S? ',' S? cp)* S? ')'
  412. *)
  413. PROCEDURE ParseContentParticle(VAR contentType: SHORTINT): XML.CollectionCP;
  414. VAR cp: XML.ContentParticle; ncp: XML.NameContentParticle; ccp: XML.CollectionCP; s: String;
  415. BEGIN
  416. IF ~CheckSymbol({Scanner.ParenOpen}, "'(' expected") THEN RETURN ccp END;
  417. scanner.ScanMarkup();
  418. IF ~CheckSymbol({Scanner.Name, Scanner.PoundName, Scanner.ParenOpen},
  419. "Element Name, '#PCDATA' or '(' expected") THEN RETURN ccp END;
  420. IF scanner.sym = Scanner.PoundName THEN
  421. contentType := XML.MixedContent;
  422. s := scanner.GetString(Scanner.Str_Other);
  423. IF s^ = '#PCDATA' THEN
  424. NEW(ncp); ncp.SetPos(scanner.GetPos()); ncp.SetNameAsString(s); ncp.SetOccurence(XML.Once);
  425. NEW(ccp); ccp.SetType(XML.Choice); ccp.AddChild(ncp);
  426. scanner.ScanMarkup();
  427. IF ~CheckSymbol({Scanner.ParenClose, Scanner.Or}, "')' or '|' expected") THEN RETURN ccp END;
  428. IF scanner.sym = Scanner.ParenClose THEN
  429. scanner.ScanMarkup();
  430. IF ~CheckSymbol({Scanner.Asterisk, Scanner.TagClose}, "'*' or '>' expected") THEN RETURN ccp END;
  431. IF scanner.sym = Scanner.Asterisk THEN
  432. ccp.SetOccurence(XML.ZeroOrMore);
  433. scanner.ScanMarkup();
  434. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN ccp END
  435. ELSIF scanner.sym = Scanner.TagClose THEN
  436. ccp.SetOccurence(XML.Once)
  437. END;
  438. cp := ccp
  439. ELSIF scanner.sym = Scanner.Or THEN
  440. WHILE scanner.sym = Scanner.Or DO
  441. scanner.ScanMarkup();
  442. IF ~CheckSymbol({Scanner.Name}, "Element Name expected") THEN RETURN ccp END;
  443. s := scanner.GetString(Scanner.Str_Other); NEW(ncp); ncp.SetPos(scanner.GetPos());
  444. ncp.SetNameAsString(s); ncp.SetOccurence(XML.Once);
  445. ccp.AddChild(ncp);
  446. scanner.ScanMarkup();
  447. IF ~CheckSymbol({Scanner.ParenClose, Scanner.Or}, "')' or '|' expected") THEN RETURN ccp END
  448. END;
  449. scanner.ScanMarkup();
  450. IF ~CheckSymbol({Scanner.Asterisk}, "'*' expected") THEN RETURN ccp END;
  451. ccp.SetOccurence(XML.ZeroOrMore);
  452. scanner.ScanMarkup();
  453. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN ccp END;
  454. cp := ccp
  455. END
  456. ELSE
  457. Error('"#PCDATA" expected'); RETURN ccp
  458. END
  459. ELSE
  460. cp := ParseElementContent();
  461. IF ~CheckSymbol({Scanner.Or, Scanner.Comma, Scanner.ParenClose}, "'|' or ',' expected") THEN RETURN ccp END;
  462. IF scanner.sym = Scanner.Or THEN
  463. NEW(ccp);
  464. ccp.SetType(XML.Choice); ccp.AddChild(cp);
  465. REPEAT
  466. scanner.ScanMarkup();
  467. ccp.AddChild(ParseElementContent());
  468. IF ~CheckSymbol({Scanner.Or, Scanner.ParenClose}, "'|' or ')' expected") THEN RETURN ccp END;
  469. UNTIL scanner.sym = Scanner.ParenClose;
  470. cp := ccp
  471. ELSIF scanner.sym = Scanner.Comma THEN
  472. NEW(ccp);
  473. ccp.SetType(XML.Sequence); ccp.AddChild(cp);
  474. REPEAT
  475. scanner.ScanMarkup();
  476. ccp.AddChild(ParseElementContent());
  477. IF ~CheckSymbol({Scanner.Comma, Scanner.ParenClose}, "',' or ')' expected") THEN RETURN ccp END;
  478. UNTIL scanner.sym = Scanner.ParenClose;
  479. cp := ccp
  480. ELSIF scanner.sym = Scanner.ParenClose THEN
  481. NEW(ccp);
  482. ccp.SetType(XML.Sequence); ccp.AddChild(cp);
  483. cp := ccp;
  484. END;
  485. scanner.ScanMarkup();
  486. CASE scanner.sym OF
  487. | Scanner.Question: cp.SetOccurence(XML.ZeroOrOnce);
  488. scanner.ScanMarkup(); IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN ccp END
  489. | Scanner.TagPIClose: cp.SetOccurence(XML.ZeroOrOnce)
  490. | Scanner.Asterisk: cp.SetOccurence(XML.ZeroOrMore);
  491. scanner.ScanMarkup(); IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN ccp END
  492. | Scanner.Plus: cp.SetOccurence(XML.OnceOrMore);
  493. scanner.ScanMarkup(); IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN ccp END
  494. ELSE cp.SetOccurence(XML.Once);
  495. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN ccp END
  496. END
  497. END;
  498. RETURN cp(XML.CollectionCP)
  499. END ParseContentParticle;
  500. PROCEDURE ParseElementContent(): XML.ContentParticle;
  501. VAR cp: XML.ContentParticle; ncp: XML.NameContentParticle; ccp: XML.CollectionCP; s: String;
  502. BEGIN
  503. IF ~CheckSymbol({Scanner.Name, Scanner.ParenOpen}, "Element Name or '(' expected") THEN RETURN cp END;
  504. IF scanner.sym = Scanner.Name THEN
  505. NEW(ncp); ncp.SetPos(scanner.GetPos()); s := scanner.GetString(Scanner.Str_Other);
  506. ncp.SetNameAsString(s); cp := ncp
  507. ELSIF scanner.sym = Scanner.ParenOpen THEN
  508. scanner.ScanMarkup();
  509. cp := ParseElementContent();
  510. IF ~CheckSymbol({Scanner.Or, Scanner.Comma}, "'|' or ',' expected") THEN RETURN cp END;
  511. IF scanner.sym = Scanner.Or THEN
  512. NEW(ccp); ccp.SetPos(scanner.GetPos());
  513. ccp.SetType(XML.Choice); ccp.AddChild(cp);
  514. REPEAT
  515. scanner.ScanMarkup();
  516. ccp.AddChild(ParseElementContent());
  517. IF ~CheckSymbol({Scanner.Or, Scanner.ParenClose}, "'|' or ')' expected") THEN RETURN cp END;
  518. UNTIL scanner.sym = Scanner.ParenClose;
  519. cp := ccp
  520. ELSIF scanner.sym = Scanner.Comma THEN
  521. NEW(ccp); ccp.SetPos(scanner.GetPos());
  522. ccp.SetType(XML.Sequence); ccp.AddChild(cp);
  523. REPEAT
  524. scanner.ScanMarkup();
  525. ccp.AddChild(ParseElementContent());
  526. IF ~CheckSymbol({Scanner.Comma, Scanner.ParenClose}, "',' or ')' expected") THEN RETURN cp END
  527. UNTIL scanner.sym = Scanner.ParenClose;
  528. cp := ccp
  529. END
  530. END;
  531. scanner.ScanMarkup();
  532. CASE scanner.sym OF
  533. | Scanner.Question: cp.SetOccurence(XML.ZeroOrOnce); scanner.ScanMarkup()
  534. | Scanner.Asterisk: cp.SetOccurence(XML.ZeroOrMore); scanner.ScanMarkup()
  535. | Scanner.Plus: cp.SetOccurence(XML.OnceOrMore); scanner.ScanMarkup()
  536. ELSE cp.SetOccurence(XML.Once)
  537. END;
  538. RETURN cp
  539. END ParseElementContent;
  540. PROCEDURE ParseEntityDecl(dtd: XML.DocTypeDecl);
  541. VAR ed: XML.EntityDecl; s: String;
  542. BEGIN
  543. NEW(ed);
  544. ed.SetPos(scanner.GetPos());
  545. scanner.ScanMarkup();
  546. IF scanner.sym = Scanner.Percent THEN (* Parameter Entity Decl *)
  547. ed.SetType(XML.ParameterEntity);
  548. scanner.ScanMarkup()
  549. ELSE (* General Entity Declaration *)
  550. ed.SetType(XML.GeneralEntity);
  551. END;
  552. IF ~CheckSymbol({Scanner.Name}, "Entity Declaration Name expected") THEN RETURN END;
  553. s := scanner.GetString(Scanner.Str_Other);
  554. ed.SetNameAsString(s);
  555. scanner.ScanMarkup();
  556. IF ~CheckSymbol({Scanner.Literal, Scanner.Name}, "EntityValue, 'SYSTEM' or 'PUBLIC' expected") THEN RETURN END;
  557. IF scanner.sym = Scanner.Literal THEN (* EntityValue *)
  558. s := ParseEntityValue();
  559. ed.SetValue(s^);
  560. scanner.ScanMarkup()
  561. ELSIF scanner.sym = Scanner.Name THEN (* ExternalID *)
  562. s := scanner.GetString(Scanner.Str_Other);
  563. IF s^ = 'SYSTEM' THEN
  564. s := ParseSystemLiteral();
  565. ed.SetSystemId(s^);
  566. scanner.ScanMarkup()
  567. ELSIF s^ = 'PUBLIC' THEN
  568. s := ParsePubidLiteral();
  569. ed.SetPublicId(s^);
  570. s := ParseSystemLiteral();
  571. ed.SetSystemId(s^);
  572. scanner.ScanMarkup()
  573. ELSE
  574. Error("'SYSTEM' or 'PUBLIC' expected"); RETURN
  575. END;
  576. IF (scanner.sym = Scanner.Name) & (ed.GetType() = XML.GeneralEntity) THEN
  577. s := scanner.GetString(Scanner.Str_Other);
  578. IF s^ = 'NDATA' THEN (* NDataDecl *)
  579. scanner.ScanMarkup();
  580. IF ~CheckSymbol({Scanner.Name}, "Notation Name expected") THEN RETURN END;
  581. s := scanner.GetString(Scanner.Str_Other);
  582. ed.SetNotationName(s^);
  583. scanner.ScanMarkup()
  584. ELSE
  585. Error("'NDATA' expected"); RETURN
  586. END
  587. END
  588. ELSE
  589. Error("EntityValue or SystemId expected"); RETURN
  590. END;
  591. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN END;
  592. dtd.AddMarkupDecl(ed)
  593. END ParseEntityDecl;
  594. PROCEDURE ParseNotationDecl(dtd: XML.DocTypeDecl);
  595. VAR nd: XML.NotationDecl; s: String;
  596. BEGIN
  597. NEW(nd); nd.SetPos(scanner.GetPos());
  598. scanner.ScanMarkup();
  599. IF ~CheckSymbol({Scanner.Name}, "Notation Name expected") THEN RETURN END;
  600. s := scanner.GetString(Scanner.Str_Other);
  601. nd.SetNameAsString(s);
  602. scanner.ScanMarkup();
  603. IF ~CheckSymbol({Scanner.Name}, "'PUBLIC' or 'SYSTEM' expected") THEN RETURN END;
  604. s := scanner.GetString(Scanner.Str_Other);
  605. IF s^ = 'PUBLIC' THEN
  606. s := ParsePubidLiteral();
  607. nd.SetPublicId(s^);
  608. scanner.ScanMarkup();
  609. IF scanner.sym = Scanner.Literal THEN (* ExternalID 1 *)
  610. s := scanner.GetString(Scanner.Str_Other);
  611. nd.SetSystemId(s^);
  612. scanner.ScanMarkup()
  613. ELSE (* PublicID, nothing more *)
  614. END
  615. ELSIF s^ = 'SYSTEM' THEN (* ExternalID 2 *)
  616. s := ParseSystemLiteral();
  617. nd.SetSystemId(s^);
  618. scanner.ScanMarkup()
  619. END;
  620. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN END;
  621. dtd.AddMarkupDecl(nd)
  622. END ParseNotationDecl;
  623. PROCEDURE ParseSystemLiteral(): String;
  624. VAR systemLiteral: String;
  625. BEGIN
  626. scanner.ScanMarkup();
  627. IF ~CheckSymbol({Scanner.Literal}, "System Literal expected") THEN RETURN systemLiteral END;
  628. systemLiteral := scanner.GetString(Scanner.Str_SystemLiteral);
  629. RETURN systemLiteral
  630. END ParseSystemLiteral;
  631. PROCEDURE ParsePubidLiteral(): String;
  632. VAR pubidLiteral: String;
  633. BEGIN
  634. scanner.ScanMarkup();
  635. IF ~CheckSymbol({Scanner.Literal}, "PubidLiteral expected") THEN RETURN pubidLiteral END;
  636. pubidLiteral := scanner.GetString(Scanner.Str_PublicLiteral);
  637. IF ~IsPubidLiteral(pubidLiteral^) THEN Error("not a correct Pubid Literal"); RETURN pubidLiteral END;
  638. RETURN pubidLiteral
  639. END ParsePubidLiteral;
  640. PROCEDURE ParseCDataSect(): XML.CDataSect;
  641. VAR cds: XML.CDataSect; s: String;
  642. BEGIN
  643. NEW(cds); cds.SetPos(scanner.GetPos());
  644. s := scanner.GetString(Scanner.Str_CDataSection);
  645. cds.SetStrAsString(s);
  646. RETURN cds
  647. END ParseCDataSect;
  648. PROCEDURE ParseCharData(): XML.ArrayChars;
  649. VAR cd: XML.ArrayChars; oldpos: LONGINT; s,s2: String;
  650. BEGIN
  651. oldpos := scanner.GetOldPos();
  652. NEW(cd); (* cd.SetFilePos(scanner.GetFile(), scanner.GetOldPos()); cd.SetLen(scanner.GetPos() - oldpos); *)
  653. cd.SetPos(scanner.GetPos());
  654. s := scanner.GetString(Scanner.Str_CharData);
  655. s := ExpandCharacterRefs(s);
  656. cd.SetStrAsString(s);
  657. RETURN cd
  658. END ParseCharData;
  659. PROCEDURE ParseElement(): XML.Element;
  660. VAR e: XML.Element; c: XML.Content; empty: BOOLEAN;
  661. BEGIN
  662. ParseStartTag(e, empty);
  663. IF e = NIL THEN RETURN NIL END;
  664. IF ~empty THEN
  665. REPEAT
  666. scanner.ScanContent();
  667. CASE scanner.sym OF
  668. | Scanner.CharData: c := ParseCharData();
  669. | Scanner.TagElemStartOpen: c := ParseElement();
  670. | Scanner.CharRef: c := ParseCharRef();
  671. | Scanner.EntityRef: c := ParseEntityRef();
  672. | Scanner.CDataSect: c := ParseCDataSect();
  673. | Scanner.Comment: c := ParseComment();
  674. | Scanner.TagPIOpen: c := ParseProcessingInstruction();
  675. | Scanner.TagElemEndOpen: c := NIL; (* do nothing *)
  676. | Scanner.Eof: Error("element not closed"); RETURN e
  677. ELSE
  678. Error("unknown Element Content"); RETURN e
  679. END;
  680. IF c # NIL THEN e.AddContent(c) END;
  681. UNTIL scanner.sym = Scanner.TagElemEndOpen;
  682. ParseEndTag(e);
  683. END;
  684. RETURN e
  685. END ParseElement;
  686. PROCEDURE ParseStartTag(VAR e: XML.Element; VAR empty: BOOLEAN);
  687. VAR s: String; pos: LONGINT; firstInstantiationFailed: BOOLEAN;
  688. BEGIN
  689. pos := scanner.GetOldPos();
  690. scanner.ScanMarkup();
  691. IF ~CheckSymbol({Scanner.Name}, "Element Name expected") THEN RETURN END;
  692. s := scanner.GetString(Scanner.Str_ElementName);
  693. IF elemReg # NIL THEN
  694. e := elemReg.InstantiateElement(s^)
  695. END;
  696. IF e = NIL THEN
  697. firstInstantiationFailed := TRUE; NEW(e)
  698. ELSE
  699. firstInstantiationFailed := FALSE;
  700. END;
  701. e.SetPos(scanner.GetPos());
  702. e.SetNameAsString(s);
  703. scanner.ScanMarkup();
  704. WHILE scanner.sym = Scanner.Name DO
  705. e.AddAttribute(ParseAttribute());
  706. scanner.ScanMarkup();
  707. END;
  708. IF (elemReg # NIL) & (firstInstantiationFailed) THEN
  709. e := elemReg.InstantiateLate(e);
  710. e.SetNameAsString(s);
  711. END;
  712. IF ~CheckSymbol({Scanner.TagEmptyElemClose, Scanner.TagClose}, "'/>' or '>' expected") THEN RETURN END;
  713. IF scanner.sym = Scanner.TagEmptyElemClose THEN
  714. empty := TRUE
  715. ELSIF scanner.sym = Scanner.TagClose THEN
  716. empty := FALSE
  717. END
  718. END ParseStartTag;
  719. PROCEDURE ParseAttribute(): XML.Attribute;
  720. VAR a: XML.Attribute; s: String;
  721. BEGIN
  722. NEW(a); a.SetPos(scanner.GetPos());
  723. s := scanner.GetString(Scanner.Str_AttributeName);
  724. a.SetNameAsString(s);
  725. scanner.ScanMarkup();
  726. IF ~CheckSymbol({Scanner.Equal}, "'=' expected") THEN RETURN a END;
  727. scanner.ScanMarkup();
  728. IF ~CheckSymbol({Scanner.Literal}, "Attribute Value expected") THEN RETURN a END;
  729. s := ParseAttributeValue();
  730. a.SetValueAsString(s);
  731. RETURN a
  732. END ParseAttribute;
  733. PROCEDURE ParseEndTag(e: XML.Element);
  734. VAR ds: DynamicStrings.DynamicString; s1, s2: String; msg: ARRAY 12 OF CHAR;
  735. BEGIN
  736. scanner.ScanMarkup();
  737. s1 := scanner.GetString(Scanner.Str_ElementName); s2 := e.GetName();
  738. IF (scanner.sym = Scanner.Name) & (s1^ = s2^) THEN
  739. scanner.ScanMarkup();
  740. IF ~CheckSymbol({Scanner.TagClose}, "'>' expected") THEN RETURN END;
  741. ELSE
  742. NEW(ds);
  743. msg := "'</'"; ds.Append(msg); ds.Append(s2^);
  744. msg := ">' expected"; ds.Append(msg); s1 := ds.ToArrOfChar();
  745. Error(s1^); RETURN
  746. END
  747. END ParseEndTag;
  748. PROCEDURE ExpandCharacterRefs(s: String): String;
  749. VAR
  750. from, to: LONGINT;
  751. ch : CHAR;
  752. PROCEDURE ReplaceEntity(CONST source: ARRAY OF CHAR; VAR srcPos: LONGINT; VAR dest: ARRAY OF CHAR; VAR destPos: LONGINT);
  753. VAR ch: CHAR; name: ARRAY 32 OF CHAR; sp, dp: LONGINT; string: Strings.String; pos: LONGINT;
  754. BEGIN
  755. ASSERT(source[srcPos] = "&");
  756. sp := srcPos+1;
  757. REPEAT
  758. ch := source[sp];
  759. name[dp] := ch;
  760. INC(sp); INC(dp);
  761. UNTIL (ch = ";") OR (ch = 0X) OR (dp >= LEN(name));
  762. name[dp-1] := 0X;
  763. IF ch = ";" THEN
  764. string := ExpandPredefinedEntity(name);
  765. IF string # NIL THEN
  766. pos := 0;
  767. REPEAT
  768. ch := string[pos];
  769. dest[destPos] := ch;
  770. INC(pos); INC(destPos);
  771. UNTIL ch = 0X;
  772. srcPos := sp -1;
  773. DEC(destPos);
  774. END;
  775. END;
  776. INC(srcPos);
  777. END ReplaceEntity;
  778. BEGIN
  779. (* we make use of the fact that the "expansion" is actually always a shrinkage and therefore make change in place ! *)
  780. to := 0; from := 0;
  781. WHILE (s[from] # "&") & (s[from] # 0X) DO
  782. INC(from); INC(to);
  783. END;
  784. REPEAT
  785. ch := s[from];
  786. IF ch = "&" THEN
  787. ReplaceEntity(s^, from, s^, to);
  788. ELSE
  789. s[to] := ch;
  790. INC(from); INC(to);
  791. END;
  792. UNTIL ch = 0X;
  793. RETURN s
  794. (*
  795. END;
  796. s[to] := 0X;
  797. s := scanner.GetString(Scanner.Str_AttributeValue);
  798. ds1.Clear; ds1.Append(s^);
  799. start := 0; len := ds1.Length(); expanded := FALSE;
  800. WHILE start < len DO
  801. WHILE (start < len) & (ds1.Get(start) # '&') DO
  802. INC(start)
  803. END;
  804. IF ds1.Get(start) = '&' THEN
  805. expanded := TRUE;
  806. end := start + 1;
  807. WHILE (end < len) & (ds1.Get(end) # ';') DO
  808. INC(end)
  809. END;
  810. IF ds1.Get(end) = ';' THEN
  811. ds2.Clear;
  812. s := ds1.Extract(0, start); (* literal before reference *)
  813. ds2.Append(s^);
  814. IF ds1.Get(start + 1) = '#' THEN (* character reference *)
  815. s := ds1.Extract(start + 2, end - start - 1);
  816. val := StrToInt(s^);
  817. msg[0] := ExpandCharacterRef(val);
  818. msg[1] := 0X;
  819. ds2.Append(msg);
  820. start := start + 1;
  821. ELSE (* predefined entity or general entity reference *)
  822. s := ds1.Extract(start + 1, end - start - 1); (* reference name *)
  823. es := ExpandPredefinedEntity(s^);
  824. IF (es # NIL) THEN
  825. start := start + 1; (* don't expand reference again *)
  826. ELSE
  827. es := ExpandEntityRef(s^, XML.GeneralEntity); (* reference value *)
  828. END;
  829. IF es = NIL THEN
  830. NEW(ds2);
  831. msg := 'unknown entity "'; ds2.Append(msg);
  832. es := ds1.Extract(start + 1, end - start - 1); ds2.Append(es^);
  833. msg := '"'; ds2.Append(msg);
  834. es := ds2.ToArrOfChar();
  835. Error(es^); RETURN ds1.ToArrOfChar()
  836. END;
  837. ds2.Append(es^);
  838. END;
  839. s := ds1.Extract(end + 1, len - end -1); (* literal after reference *)
  840. ds2.Append(s^);
  841. ds1.CopyFrom(ds2, 0, ds2.Length());
  842. len := ds1.Length()
  843. ELSE
  844. Error("';' expected (unclosed reference)"); RETURN ds1.ToArrOfChar()
  845. END
  846. END
  847. END;
  848. IF expanded THEN
  849. RETURN ds1.ToArrOfChar();
  850. ELSE
  851. RETURN s;
  852. END;
  853. *)
  854. END ExpandCharacterRefs;
  855. PROCEDURE ParseEntityValue(): String;
  856. VAR s, es: String; start, end, len, val: LONGINT; msg: ARRAY 17 OF CHAR;
  857. BEGIN
  858. ds1.Clear; ds1.Append(s^);
  859. start := 0; len := ds1.Length();
  860. WHILE start < len DO
  861. WHILE (start < len) & ((ds1.Get(start) # '&') OR (ds1.Get(start + 1) # '#')) & (ds1.Get(start) # '%') DO
  862. INC(start)
  863. END;
  864. IF ((ds1.Get(start) = '&') & (ds1.Get(start + 1) = '#')) OR (ds1.Get(start) = '%') THEN
  865. end := start + 1;
  866. WHILE (end < len) & (ds1.Get(end) # ';') DO
  867. INC(end)
  868. END;
  869. IF ds1.Get(end) = ';' THEN
  870. ds2.Clear;
  871. s := ds1.Extract(0, start); (* literal before reference *)
  872. ds2.Append(s^);
  873. IF (ds1.Get(start) = '&') & (ds1.Get(start + 1) = '#') THEN (* character reference *)
  874. s := ds1.Extract(start + 2, end - start - 1);
  875. val := StrToInt(s^);
  876. msg[0] := ExpandCharacterRef(val);
  877. msg[1] := 0X;
  878. ds2.Append(msg);
  879. start := start + 1;
  880. ELSE (* predefined entity or parameter entity reference *)
  881. s := ds1.Extract(start + 1, end - start - 1); (* reference name *)
  882. es := ExpandPredefinedEntity(s^);
  883. IF (es # NIL) THEN
  884. start := start + 1; (* don't expand reference again *)
  885. ELSE
  886. es := ExpandEntityRef(s^, XML.ParameterEntity); (* reference value *)
  887. END;
  888. IF es = NIL THEN
  889. NEW(ds2);
  890. msg := 'unknown entity "'; ds2.Append(msg);
  891. es := ds1.Extract(start + 1, end - start - 1); ds2.Append(es^);
  892. msg := '"'; ds2.Append(msg);
  893. es := ds2.ToArrOfChar();
  894. Error(es^); RETURN ds1.ToArrOfChar()
  895. END;
  896. ds2.Append(es^);
  897. END;
  898. s := ds1.Extract(end + 1, len - end -1); (* literal after reference *)
  899. ds2.Append(s^);
  900. ds1.CopyFrom(ds2, 0, ds2.Length());
  901. len := ds1.Length()
  902. ELSE
  903. Error("';' expected (unclosed reference)"); RETURN ds1.ToArrOfChar()
  904. END
  905. END
  906. END;
  907. RETURN ds1.ToArrOfChar()
  908. END ParseEntityValue;
  909. PROCEDURE ParseAttributeValue(): String;
  910. VAR
  911. s, es: String; start, end, len, val: LONGINT; msg: ARRAY 17 OF CHAR;
  912. expanded : BOOLEAN;
  913. BEGIN
  914. s := scanner.GetString(Scanner.Str_AttributeValue);
  915. RETURN ExpandCharacterRefs(s);
  916. END ParseAttributeValue;
  917. PROCEDURE ParseCharRef(): XML.CharReference;
  918. VAR cRef: XML.CharReference; code: LONGINT; res: WORD; s: String;
  919. BEGIN
  920. s := scanner.GetString(Scanner.CharRef);
  921. IF s[0] = 'x' THEN (* hexadecimal *)
  922. Strings.Delete(s^, 0, 1);
  923. Strings.HexStrToInt(s^, code, res);
  924. ELSE (* decimal *)
  925. Strings.StrToInt(s^, code);
  926. END;
  927. NEW(cRef); cRef.SetPos(scanner.GetPos());
  928. cRef.SetCode(code);
  929. RETURN cRef;
  930. END ParseCharRef;
  931. PROCEDURE ParseEntityRef(): XML.EntityRef;
  932. VAR ext: XML.ExternalEntityRef; int: XML.InternalEntityRef; s1, s2: String; ent: XML.EntityDecl;
  933. BEGIN
  934. s1 := scanner.GetString(Scanner.Str_EntityRef);
  935. ent := dtd.GetEntityDecl(s1^, XML.GeneralEntity);
  936. IF ent # NIL THEN
  937. s2 := ent.GetValue();
  938. IF s2 # NIL THEN
  939. NEW(int); int.SetPos(scanner.GetPos());
  940. int.SetNameAsString(s1);
  941. RETURN int
  942. ELSE
  943. NEW(ext); ext.SetPos(scanner.GetPos());
  944. ext.SetNameAsString(s1);
  945. RETURN ext
  946. END
  947. ELSE
  948. RETURN NIL
  949. END
  950. END ParseEntityRef;
  951. END Parser;
  952. VAR
  953. (* read-only *)
  954. predefinedEntities : ARRAY 5 OF RECORD name : ARRAY 5 OF CHAR; expanded : Strings.String; END;
  955. PROCEDURE IsPubidLiteral(CONST str: ARRAY OF CHAR): BOOLEAN;
  956. VAR i, len: LONGINT; ch: CHAR;
  957. BEGIN
  958. i := 0; len := LEN(str); ch := str[0];
  959. REPEAT
  960. ch := str[i]; INC(i)
  961. UNTIL ((ch # 20X) & (ch # 0DX) & (ch # 0AX) & ((ch < 'a') OR ('z' < ch)) & ((ch < 'A') & ('Z' < ch))
  962. & ((ch < '0') & ('9' < ch)) & (ch # '(') & (ch # ')') & (ch # '+') & (ch # ',') & (ch # '.')
  963. & (ch # '/') & (ch # ':') & (ch # '=') & (ch # '?') & (ch # ';') & (ch # '!') & (ch # '*') & (ch # '#')
  964. & (ch # '@') & (ch # '$') & (ch # '_') & (ch # '%')) OR (i >= len);
  965. RETURN i = len
  966. END IsPubidLiteral;
  967. PROCEDURE StrToInt(VAR str: ARRAY OF CHAR): LONGINT;
  968. BEGIN
  969. IF str[0] = 'x' THEN (* str in hexadecimal form *)
  970. str[0] := ' ';
  971. RETURN DynamicStrings.HexStrToInt(str)
  972. ELSE
  973. RETURN DynamicStrings.StrToInt(str)
  974. END
  975. END StrToInt;
  976. PROCEDURE DefaultReportError(pos, line, col: LONGINT; CONST msg: ARRAY OF CHAR);
  977. BEGIN
  978. KernelLog.Enter; KernelLog.Char(CHR(9H)); KernelLog.Char(CHR(9H)); KernelLog.String("pos "); KernelLog.Int(pos, 6);
  979. KernelLog.String(", line "); KernelLog.Int(line, 0); KernelLog.String(", column "); KernelLog.Int(col, 0);
  980. KernelLog.String(" "); KernelLog.String(msg); KernelLog.Exit;
  981. END DefaultReportError;
  982. PROCEDURE ExpandPredefinedEntity(CONST name : ARRAY OF CHAR) : Strings.String;
  983. VAR i : LONGINT;
  984. BEGIN
  985. FOR i := 0 TO LEN(predefinedEntities)-1 DO
  986. IF (name = predefinedEntities[i].name) THEN
  987. RETURN predefinedEntities[i].expanded;
  988. END;
  989. END;
  990. RETURN NIL;
  991. END ExpandPredefinedEntity;
  992. PROCEDURE Init;
  993. BEGIN
  994. predefinedEntities[0].name := "lt"; predefinedEntities[0].expanded := Strings.NewString("<");
  995. predefinedEntities[1].name := "gt"; predefinedEntities[1].expanded := Strings.NewString(">");
  996. predefinedEntities[2].name := "amp"; predefinedEntities[2].expanded := Strings.NewString("&");
  997. predefinedEntities[3].name := "apos"; predefinedEntities[3].expanded := Strings.NewString("'");
  998. predefinedEntities[4].name := "quot"; predefinedEntities[4].expanded := Strings.NewString('"');
  999. END Init;
  1000. BEGIN
  1001. Init;
  1002. END XMLParser.