1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864 |
- MODULE XML; (** AUTHOR "swalthert"; PURPOSE "XML base"; *)
- IMPORT
- Streams, Strings, UTF8Strings, Modules, DynamicStrings, Objects := XMLObjects, KernelLog;
- CONST
- Ok* = 0;
- InvalidString* = 1;
- BufferError* = 2;
- Tab = DynamicStrings.Tab;
- Space = 20X;
- TYPE
- String* = Strings.String;
- TYPE
- Content* = OBJECT
- VAR
- pos: LONGINT;
- previous, next : Content;
- PROCEDURE &Init*;
- BEGIN
- pos := 0;
- previous := NIL; next := NIL;
- END Init;
- PROCEDURE GetPos*(): LONGINT;
- BEGIN
- RETURN pos
- END GetPos;
- PROCEDURE SetPos*(pos : LONGINT);
- BEGIN
- SELF.pos := pos
- END SetPos;
- (** write the content to stream w. level is the current hierarchy level. used for formatting *)
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- END Write;
- END Content;
- NameContent* = OBJECT (Content)
- VAR
- name: String;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- name := StrNoName;
- END Init;
- PROCEDURE GetName*(): String;
- BEGIN
- RETURN name
- END GetName;
- PROCEDURE SetName*(CONST name: ARRAY OF CHAR);
- BEGIN
- SELF.name := NewString(name)
- END SetName;
- PROCEDURE SetNameAsString*(name : String);
- BEGIN
- IF (name # NIL) THEN
- SELF.name := name;
- ELSE
- SELF.name := StrNoName;
- END;
- END SetNameAsString;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.String(name^)
- END Write;
- END NameContent;
- Container* = OBJECT (Content)
- VAR
- first, last : Content;
- nofContents : LONGINT;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- first := NIL; last := NIL;
- nofContents := 0;
- END Init;
- PROCEDURE RemoveContent0(c: Content): BOOLEAN;
- VAR cur : Content;
- BEGIN
- (*ASSERT(c # NIL);*)
- IF c=NIL THEN RETURN FALSE END;(*PH 12/13*)
- IF (first # NIL) THEN
- IF (first = c) THEN
- IF (first.next # NIL) THEN first.next.previous := NIL; END;
- first := first.next;
- IF (last = c) THEN last := NIL; ASSERT(first = NIL); END;
- c.next := NIL; c.previous := NIL;
- RETURN TRUE
- ELSE
- cur := first;
- WHILE (cur.next # NIL) & (cur.next # c) DO cur := cur.next; END;
- IF (cur.next # NIL) THEN
- IF (cur.next.next # NIL) THEN cur.next.next.previous := cur; END;
- cur.next := cur.next.next;
- IF (last = c) THEN last := cur; ASSERT(cur.next = NIL); END;
- c.next := NIL; c.previous := NIL;
- RETURN TRUE
- END;
- END;
- END;
- RETURN FALSE
- END RemoveContent0;
- (* Move this after previous. If previous = NIL then move this to end *)
- PROCEDURE MoveContentAfter*(this, previous: Content);
- VAR current: Content;
- BEGIN{EXCLUSIVE}
- IF RemoveContent0(this) THEN
- IF (previous = NIL) OR (previous = last) THEN (* insert as last *)
- IF last = NIL THEN
- first := this; last := this
- ELSE
- last.next := this;
- this.previous := last;
- last := this;
- END;
- ELSE
- this.next := previous.next;
- this.next.previous := this;
- previous.next := this;
- this.previous := previous;
- END
- END;
- END MoveContentAfter;
- (* Move this before next. If next = NIL then move this to front *)
- PROCEDURE MoveContentBefore*(this, next: Content);
- VAR current: Content;
- BEGIN{EXCLUSIVE}
- IF RemoveContent0(this) THEN
- IF (next = NIL) OR (next = first) THEN (* insert as first *)
- IF first = NIL THEN
- first := this; last := this
- ELSE
- this.next := first;
- first.previous := this;
- first := this;
- END;
- ELSE
- next.previous.next := this;
- this.previous := next.previous;
- this.next := next;
- next.previous := this;
- END;
- END;
- END MoveContentBefore;
- PROCEDURE AddContent*(c: Content);
- BEGIN {EXCLUSIVE}
- ASSERT((c # NIL) & (c.next = NIL) & (c.previous = NIL)); (* may not be in more than one list! *)
- IF (first = NIL) THEN
- ASSERT(last = NIL);
- first := c; last := c;
- ELSE
- ASSERT(last # NIL);
- last.next := c;
- c.previous := last;
- last := c;
- END;
- ASSERT((first # NIL) & (last # NIL));
- INC(nofContents);
- END AddContent;
- PROCEDURE RemoveContent*(c: Content);
- VAR b: BOOLEAN;
- BEGIN {EXCLUSIVE}
- IF RemoveContent0(c) THEN DEC(nofContents) END
- END RemoveContent;
- PROCEDURE GetContents*(): Objects.Enumerator;
- VAR c : Content; array : Objects.PTRArray; enumerator : Objects.ArrayEnumerator; i : LONGINT;
- BEGIN {EXCLUSIVE}
- NEW(array, nofContents);
- c := first;
- FOR i := 0 TO nofContents - 1 DO
- array[i] := c;
- c := c.next;
- END;
- NEW(enumerator, array);
- RETURN enumerator;
- END GetContents;
- PROCEDURE GetNumberOfContents*(): LONGINT;
- BEGIN
- RETURN nofContents;
- END GetNumberOfContents;
- PROCEDURE GetFirst*() : Content;
- BEGIN
- RETURN first;
- END GetFirst;
- PROCEDURE GetLast*() : Content;
- BEGIN
- RETURN last;
- END GetLast;
- PROCEDURE GetNext*(content : Content) : Content;
- BEGIN
- ASSERT(content # NIL);
- RETURN content.next;
- END GetNext;
- PROCEDURE GetPrevious*(content : Content) : Content;
- BEGIN
- ASSERT(content # NIL);
- RETURN content.previous;
- END GetPrevious;
- END Container;
- TYPE
- Document* = OBJECT (Container)
- VAR
- xmldecl: XMLDecl;
- dtd: DocTypeDecl;
- root: Element;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- xmldecl := NIL;
- NEW(dtd);
- root := NIL;
- END Init;
- PROCEDURE GetXMLDecl*(): XMLDecl;
- BEGIN
- RETURN xmldecl
- END GetXMLDecl;
- PROCEDURE GetDocTypeDecl*(): DocTypeDecl;
- BEGIN
- RETURN dtd
- END GetDocTypeDecl;
- PROCEDURE GetRoot*(): Element;
- BEGIN
- RETURN root
- END GetRoot;
- PROCEDURE AddContent*(c: Content);
- BEGIN
- IF (c IS XMLDecl) & (xmldecl = NIL) THEN xmldecl := c(XMLDecl)
- ELSIF (c IS DocTypeDecl) THEN dtd := c(DocTypeDecl)
- ELSIF (c IS Element) & (root = NIL) THEN root := c(Element); root.SetDocument(SELF)
- END;
- AddContent^(c)
- END AddContent;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR e: Objects.Enumerator; c: ANY;
- BEGIN
- e := GetContents();
- WHILE e.HasMoreElements() DO
- c := e.GetNext();
- c(Content).Write(w, context, level + 1)
- END
- END Write;
- END Document;
- TextDecl* = OBJECT (Content)
- VAR
- version, encoding: String;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- version := NIL; encoding := NIL;
- END Init;
- PROCEDURE GetVersion*(): String;
- BEGIN
- RETURN version
- END GetVersion;
- PROCEDURE SetVersion*(CONST version: ARRAY OF CHAR);
- BEGIN
- SELF.version := NewString(version)
- END SetVersion;
- PROCEDURE GetEncoding*(): String;
- BEGIN
- RETURN encoding
- END GetEncoding;
- PROCEDURE SetEncoding*(CONST encoding: ARRAY OF CHAR);
- BEGIN
- SELF.encoding := NewString(encoding)
- END SetEncoding;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.String('<?xml version="'); w.String(version^);
- IF encoding # NIL THEN w.String('" encoding="'); w.String(encoding^) END;
- w.String('"?>'); NewLine(w, level)
- END Write;
- END TextDecl;
- XMLDecl* = OBJECT (TextDecl)
- VAR
- standalone: BOOLEAN;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- standalone := FALSE;
- END Init;
- PROCEDURE IsStandalone*(): BOOLEAN;
- BEGIN
- RETURN standalone
- END IsStandalone;
- PROCEDURE SetStandalone*(standalone: BOOLEAN);
- BEGIN
- SELF.standalone := standalone
- END SetStandalone;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.String('<?xml version="'); w.String(version^);
- IF encoding # NIL THEN w.String('" encoding="'); w.String(encoding^) END;
- w.String('" standalone="');
- IF standalone THEN w.String("yes") ELSE w.String("no") END;
- w.String('"?>'); NewLine(w, level)
- END Write;
- END XMLDecl;
- DocTypeDecl* = OBJECT (NameContent)
- VAR
- elementDecls, notationDecls, generalEntities, parameterEntities: Objects.Dictionary;
- allMarkupDecls: Objects.Collection;
- externalSubset: EntityDecl;
- PROCEDURE & Init*;
- VAR (* ed: EntityDecl; *) arrDict: Objects.ArrayDict; arrColl: Objects.ArrayCollection;
- BEGIN
- Init^;
- NEW(arrDict); elementDecls := arrDict;
- NEW(arrDict); notationDecls := arrDict;
- NEW(arrDict); generalEntities := arrDict;
- NEW(arrDict); parameterEntities := arrDict;
- NEW(arrColl); allMarkupDecls := arrColl;
- externalSubset := NIL;
- (* add predefined entities *)
- (* NEW(ed); NEW(ed.name, 3); ed.name[0] := 'l'; ed.name[1] := 't'; ed.name[2] := 0X;
- NEW(ed.value, 10); COPY("&#60;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
- NEW(ed); NEW(ed.name, 3); ed.name[0] := 'g'; ed.name[1] := 't'; ed.name[2] := 0X;
- NEW(ed.value, 10); COPY(">", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
- NEW(ed); NEW(ed.name, 4); ed.name[0] := 'a'; ed.name[1] := 'm'; ed.name[2] := 'p'; ed.name[3] := 0X;
- NEW(ed.value, 10); COPY("&#38;", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
- 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;
- NEW(ed.value, 10); COPY("'", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed);
- 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;
- NEW(ed.value, 10); COPY(""", ed.value^); ed.type := GeneralEntity; AddMarkupDecl(ed)
- *)
- END Init;
- PROCEDURE AddMarkupDecl*(c: Content);
- BEGIN
- IF c IS ElementDecl THEN
- elementDecls.Add(c(ElementDecl).name^, c); allMarkupDecls.Add(c)
- ELSIF (c IS EntityDecl) & (c(EntityDecl).type = GeneralEntity) THEN
- generalEntities.Add(c(EntityDecl).name^, c); allMarkupDecls.Add(c)
- ELSIF (c IS EntityDecl) & (c(EntityDecl).type = ParameterEntity) THEN
- parameterEntities.Add(c(EntityDecl).name^, c); allMarkupDecls.Add(c)
- ELSIF c IS NotationDecl THEN
- notationDecls.Add(c(NotationDecl).name^, c); allMarkupDecls.Add(c)
- ELSIF (c IS ProcessingInstruction) OR (c IS Comment) THEN
- allMarkupDecls.Add(c)
- END
- END AddMarkupDecl;
- PROCEDURE GetElementDecl*(CONST name: ARRAY OF CHAR): ElementDecl;
- VAR p: ANY;
- BEGIN
- p := elementDecls.Get(name);
- IF p # NIL THEN RETURN p(ElementDecl)
- ELSE RETURN NIL
- END
- END GetElementDecl;
- PROCEDURE GetNotationDecl*(CONST name: ARRAY OF CHAR): NotationDecl;
- VAR p: ANY;
- BEGIN
- p := elementDecls.Get(name);
- IF p # NIL THEN RETURN p(NotationDecl)
- ELSE RETURN NIL
- END
- END GetNotationDecl;
- PROCEDURE GetEntityDecl*(CONST name: ARRAY OF CHAR; type: SHORTINT): EntityDecl;
- VAR p: ANY;
- BEGIN
- p := NIL;
- IF type = GeneralEntity THEN p := generalEntities.Get(name)
- ELSIF type = ParameterEntity THEN p := parameterEntities.Get(name)
- END;
- IF p # NIL THEN RETURN p(EntityDecl)
- ELSE RETURN NIL
- END
- END GetEntityDecl;
- PROCEDURE GetExternalSubset*(): EntityDecl;
- BEGIN
- RETURN externalSubset
- END GetExternalSubset;
- PROCEDURE SetExternalSubset*(externalSubset: EntityDecl);
- BEGIN
- SELF.externalSubset := externalSubset
- END SetExternalSubset;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR e: Objects.Enumerator; p: ANY; s: String;
- BEGIN
- w.String("<!DOCTYPE "); w.String(name^);
- IF externalSubset # NIL THEN
- s := externalSubset.GetPublicId();
- IF s # NIL THEN
- w.String(' PUBLIC "'); w.String(s^); w.String('" "');
- ELSE
- w.String(' SYSTEM "')
- END;
- s := externalSubset.GetSystemId();
- w.String(s^); w.Char('"')
- END;
- e := allMarkupDecls.GetEnumerator();
- IF e.HasMoreElements() THEN
- w.String(" ["); NewLine(w, level + 1);
- WHILE e.HasMoreElements() DO
- p := e.GetNext(); p(Content).Write(w, context, level + 1)
- END;
- w.String("]")
- END;
- w.Char('>'); NewLine(w, level)
- END Write;
- END DocTypeDecl;
- NotationDecl* = OBJECT (NameContent)
- VAR
- systemId, publicId: String;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- systemId := NIL; publicId := NIL;
- END Init;
- PROCEDURE GetSystemId*(): String;
- BEGIN
- RETURN systemId
- END GetSystemId;
- PROCEDURE SetSystemId*(CONST systemId: ARRAY OF CHAR);
- BEGIN
- SELF.systemId := NewString(systemId)
- END SetSystemId;
- PROCEDURE GetPublicId*(): String;
- BEGIN
- RETURN publicId
- END GetPublicId;
- PROCEDURE SetPublicId*(CONST publicId: ARRAY OF CHAR);
- BEGIN
- SELF.publicId := NewString(publicId)
- END SetPublicId;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.String("<!NOTATION "); w.String(name^);
- IF publicId # NIL THEN
- w.String(' PUBLIC "'); w.String(publicId^); w.String('" "');
- IF systemId # NIL THEN w.String(systemId^); w.Char('"') END
- ELSE
- w.String(' SYSTEM "'); w.String(systemId^); w.Char('"')
- END;
- w.Char('>'); NewLine(w, level)
- END Write;
- END NotationDecl;
- CONST
- (** EntityDecl.SetType *)
- GeneralEntity* = 0;
- ParameterEntity* = 1;
- TYPE
- EntityDecl* = OBJECT (NotationDecl)
- VAR
- value, notationName: String;
- type: SHORTINT;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- value := NIL; notationName := NIL;
- type := GeneralEntity;
- END Init;
- PROCEDURE GetType*(): SHORTINT;
- BEGIN
- RETURN type
- END GetType;
- PROCEDURE SetType*(type: SHORTINT);
- BEGIN
- SELF.type := type
- END SetType;
- PROCEDURE GetValue*(): String;
- BEGIN
- RETURN value
- END GetValue;
- PROCEDURE SetValue*(CONST value: ARRAY OF CHAR);
- BEGIN
- SELF.value := NewString(value)
- END SetValue;
- PROCEDURE GetNotationName*(): String;
- BEGIN
- RETURN notationName
- END GetNotationName;
- PROCEDURE SetNotationName*(CONST notationName: ARRAY OF CHAR);
- BEGIN
- SELF.notationName := NewString(notationName)
- END SetNotationName;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.String("<!ENTITY ");
- IF type = ParameterEntity THEN w.String("% ") END;
- w.String(name^);
- IF value # NIL THEN
- w.String(' "'); w.String(value^); w.Char('"')
- ELSE
- IF publicId # NIL THEN
- w.String(' PUBLIC "'); w.String(publicId^); w.String('" "');
- IF systemId # NIL THEN w.String(systemId^); w.Char('"') END
- ELSE
- w.String(' SYSTEM "'); w.String(systemId^); w.Char('"')
- END;
- IF (type = GeneralEntity) & (notationName # NIL) THEN
- w.String(' NDATA '); w.String(notationName^)
- END
- END;
- w.Char('>'); NewLine(w, level)
- END Write;
- END EntityDecl;
- CONST
- (** ElementDecl.SetContentType *)
- Any* = 0; (** 'ANY' *)
- Empty* = 1; (** 'EMPTY' *)
- ElementContent* = 2; (** children *)
- MixedContent* = 3; (** Mixed *)
- TYPE
- ElementDecl* = OBJECT (NameContent)
- VAR
- contentType: SHORTINT;
- content: CollectionCP; (* for contentType = Mixed or contentType = Element *)
- attributeDecls: Objects.Dictionary;
- PROCEDURE & Init*;
- VAR arrDict: Objects.ArrayDict;
- BEGIN
- Init^;
- contentType := Any;
- content := NIL;
- NEW(arrDict); attributeDecls := arrDict
- END Init;
- PROCEDURE GetContentType*(): SHORTINT;
- BEGIN
- RETURN contentType
- END GetContentType;
- PROCEDURE SetContentType*(contentType: SHORTINT);
- BEGIN
- SELF.contentType := contentType
- END SetContentType;
- PROCEDURE GetContent*(): CollectionCP;
- BEGIN
- RETURN content
- END GetContent;
- PROCEDURE SetContent*(lcp: CollectionCP);
- BEGIN
- content := lcp
- END SetContent;
- PROCEDURE GetAttributeDecl*(CONST name: ARRAY OF CHAR): AttributeDecl;
- VAR nc: ANY;
- BEGIN
- nc := attributeDecls.Get(name);
- IF nc # NIL THEN RETURN nc (AttributeDecl) ELSE RETURN NIL END
- END GetAttributeDecl;
- PROCEDURE GetAttributeDecls*(): Objects.Enumerator;
- BEGIN
- RETURN attributeDecls.GetEnumerator()
- END GetAttributeDecls;
- PROCEDURE AddAttributeDecl*(attributeDecl: AttributeDecl);
- BEGIN
- attributeDecls.Add(attributeDecl.name^, attributeDecl)
- END AddAttributeDecl;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR e: Objects.Enumerator; p: ANY;
- BEGIN
- w.String("<!ELEMENT "); w.String(name^); w.Char(Space);
- IF contentType = Empty THEN
- w.String("EMPTY")
- ELSIF contentType = Any THEN
- w.String("ANY")
- ELSIF content # NIL THEN
- content.Write(w, context, level + 1)
- END;
- w.Char('>'); NewLine(w, level);
- e := GetAttributeDecls();
- IF e.HasMoreElements() THEN
- w.String("<!ATTLIST "); w.String(name^); NewLine(w, level+1);
- WHILE e.HasMoreElements() DO
- p := e.GetNext(); p(Content).Write(w, context, level + 1)
- END;
- w.Char('>'); NewLine(w, level)
- END
- END Write;
- END ElementDecl;
- CONST
- (** ContentParticle.SetOccurence *)
- ZeroOrOnce* = 0; (** '?' *)
- ZeroOrMore* = 1; (** '*' *)
- Once* = 2; (** nothing *)
- OnceOrMore* = 3; (** '+' *)
- TYPE
- ContentParticle* = OBJECT (Content)
- VAR
- occurence: SHORTINT;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- occurence := ZeroOrOnce;
- END Init;
- PROCEDURE GetOccurence*(): SHORTINT;
- BEGIN
- RETURN occurence
- END GetOccurence;
- PROCEDURE SetOccurence*(occ: SHORTINT);
- BEGIN
- occurence := occ
- END SetOccurence;
- PROCEDURE GetOccurenceChar(): CHAR;
- BEGIN
- CASE occurence OF
- | ZeroOrOnce: RETURN '?'
- | ZeroOrMore: RETURN '*'
- | Once: RETURN 0X
- | OnceOrMore: RETURN '+'
- END
- END GetOccurenceChar;
- END ContentParticle;
- NameContentParticle* = OBJECT (ContentParticle)
- VAR
- name: String;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- name := NIL;
- END Init;
- PROCEDURE GetName*(): String;
- BEGIN
- RETURN name
- END GetName;
- PROCEDURE SetName*(CONST name: ARRAY OF CHAR);
- BEGIN
- SELF.name := NewString(name)
- END SetName;
- PROCEDURE SetNameAsString*(name : String);
- BEGIN
- SELF.name := name;
- END SetNameAsString;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR ch: CHAR;
- BEGIN
- w.String(name^);
- ch := GetOccurenceChar(); IF ch # 0X THEN w.Char(ch) END
- END Write;
- END NameContentParticle;
- CONST
- (** CollectionCP.SetType *)
- Choice* = 1;
- Sequence* = 2;
- TYPE
- CollectionCP* = OBJECT (ContentParticle)
- VAR
- children: Objects.Collection;
- type: SHORTINT;
- PROCEDURE & Init*;
- VAR arrColl: Objects.ArrayCollection;
- BEGIN
- Init^;
- NEW(arrColl); children := arrColl;
- type := 0;
- END Init;
- PROCEDURE GetType*(): SHORTINT;
- BEGIN
- RETURN type
- END GetType;
- PROCEDURE SetType*(type: SHORTINT);
- BEGIN
- SELF.type := type
- END SetType;
- PROCEDURE GetChildren*(): Objects.Enumerator;
- BEGIN
- RETURN children.GetEnumerator()
- END GetChildren;
- PROCEDURE AddChild*(cp: ContentParticle);
- BEGIN
- children.Add(cp)
- END AddChild;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR e: Objects.Enumerator; ch: CHAR; p: ANY;
- BEGIN
- e := GetChildren();
- p := e.GetNext();
- w.Char('(');
- p(Content).Write(w, context, level + 1);
- WHILE e.HasMoreElements() DO
- p := e.GetNext();
- IF type = Choice THEN w.String(" | ")
- ELSIF type = Sequence THEN w.String(", ")
- END;
- p(Content).Write(w, context, level + 1)
- END;
- w.Char(')');
- ch := GetOccurenceChar(); IF ch # 0X THEN w.Char(ch) END
- END Write;
- END CollectionCP;
- CONST
- (** AttributeDecl.SetType *)
- CData* = 0; (** CDATA *)
- Id* = 1; (** ID *)
- IdRef* = 2; (** IDREF *)
- IdRefs* = 3; (** IDREFS *)
- Entity* = 4; (** ENTITY *)
- Entities* = 5; (** ENTITIES *)
- NmToken* = 6; (** NMTOKEN *)
- NmTokens* = 7; (** NMTOKENS *)
- Notation* = 8; (** NOTATION *)
- Enumeration* = 9; (** Enumeration *)
- TYPE
- AttributeDecl* = OBJECT (NameContent)
- VAR
- defaultValue: String;
- type: SHORTINT;
- allowedValues: Objects.Dictionary;
- required: BOOLEAN;
- PROCEDURE &Init*;
- VAR arrDict: Objects.ArrayDict;
- BEGIN
- Init^;
- defaultValue := NIL;
- type := CData;
- NEW(arrDict); allowedValues := arrDict;
- required := FALSE;
- END Init;
- PROCEDURE GetDefaultValue*(): String;
- BEGIN
- RETURN defaultValue
- END GetDefaultValue;
- PROCEDURE SetDefaultValue*(CONST defaultValue: ARRAY OF CHAR);
- BEGIN
- SELF.defaultValue := NewString(defaultValue)
- END SetDefaultValue;
- PROCEDURE GetType*(): SHORTINT;
- BEGIN
- RETURN type
- END GetType;
- PROCEDURE SetType*(type: SHORTINT);
- BEGIN
- SELF.type := type
- END SetType;
- (** Collection of NameContents *)
- PROCEDURE GetAllowedValues*(): Objects.Enumerator;
- BEGIN
- RETURN allowedValues.GetEnumerator()
- END GetAllowedValues;
- PROCEDURE AddAllowedValue*(CONST value: ARRAY OF CHAR);
- VAR nameContent: NameContent;
- BEGIN
- NEW(nameContent); nameContent.SetName(value);
- allowedValues.Add(value, nameContent)
- END AddAllowedValue;
- PROCEDURE IsRequired*(): BOOLEAN;
- BEGIN
- RETURN required
- END IsRequired;
- PROCEDURE SetRequired*(required: BOOLEAN);
- BEGIN
- SELF.required := required
- END SetRequired;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR e: Objects.Enumerator; p: ANY;
- BEGIN
- w.String(name^); w.Char(Space);
- CASE type OF
- | CData: w.String("CDATA")
- | Id: w.String("ID")
- | IdRef: w.String("IDREF")
- | IdRefs: w.String("IDREFS")
- | Entity: w.String("ENTITY")
- | Entities: w.String("ENTITIES")
- | NmToken: w.String("NMTOKEN")
- | NmTokens: w.String("NMTOKENS")
- | Notation: w.String("NOTATION")
- | Enumeration:
- END;
- IF type # Enumeration THEN w.Char(Space) END;
- IF (type = Notation) OR (type = Enumeration) THEN
- w.Char('('); e := GetAllowedValues();
- p := e.GetNext(); p(Content).Write(w, context, level + 1);
- WHILE e.HasMoreElements() DO
- w.Char('|'); p := e.GetNext(); p(Content).Write(w, context, level + 1)
- END;
- w.String(") ")
- END;
- IF required THEN
- IF defaultValue = NIL THEN w.String('#REQUIRED')
- ELSE w.String('#FIXED "'); w.String(defaultValue^); w.String('"')
- END
- ELSE
- IF defaultValue = NIL THEN w.String('#IMPLIED')
- ELSE w.String('"'); w.String(defaultValue^); w.String('"')
- END
- END;
- NewLine(w, level)
- END Write;
- END AttributeDecl;
- TYPE
- CharReference* = OBJECT (Content)
- VAR
- code: LONGINT;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- code := 0;
- END Init;
- PROCEDURE SetCode*(code: LONGINT);
- BEGIN
- SELF.code := code
- END SetCode;
- PROCEDURE GetCode*(): LONGINT;
- BEGIN
- RETURN code
- END GetCode;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR codeArray: ARRAY 16 OF CHAR; codeStr: String;
- BEGIN
- DynamicStrings.IntToStr(code, codeArray);
- codeStr := NewString(codeArray);
- w.String('&#'); w.String(codeStr^); w.Char(';')
- END Write;
- END CharReference;
- TYPE
- EntityRef* = OBJECT (NameContent)
- VAR
- decl: EntityDecl;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- decl := NIL;
- END Init;
- PROCEDURE GetEntityDecl*(): EntityDecl;
- BEGIN
- RETURN decl
- END GetEntityDecl;
- PROCEDURE SetDocument(document: Document);
- VAR dtd: DocTypeDecl;
- BEGIN
- dtd := document.GetDocTypeDecl();
- IF dtd # NIL THEN
- decl := dtd.GetEntityDecl(name^, GeneralEntity)
- END
- END SetDocument;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.Char('&'); w.String(name^); w.Char(';')
- END Write;
- END EntityRef;
- TYPE
- InternalEntityRef* = OBJECT (EntityRef)
- PROCEDURE GetValue*(): String;
- BEGIN
- IF decl # NIL THEN RETURN decl.value
- ELSE RETURN NIL
- END
- END GetValue;
- END InternalEntityRef;
- TYPE
- ExternalEntityRef* = OBJECT (EntityRef)
- VAR
- coll: Objects.Collection;
- textDecl: TextDecl;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- coll := NIL;
- textDecl := NIL;
- END Init;
- PROCEDURE GetTextDecl*(): TextDecl;
- BEGIN
- RETURN textDecl
- END GetTextDecl;
- PROCEDURE GetContents*(): Objects.Enumerator;
- BEGIN
- IF IsParsed() THEN RETURN coll.GetEnumerator()
- ELSE RETURN NIL
- END
- END GetContents;
- PROCEDURE AddContent*(c: Content);
- VAR arrColl: Objects.ArrayCollection;
- BEGIN
- IF coll = NIL THEN NEW(arrColl); coll := arrColl END;
- IF c IS TextDecl THEN
- textDecl := c(TextDecl)
- END;
- coll.Add(c)
- END AddContent;
- PROCEDURE IsParsed*(): BOOLEAN;
- BEGIN
- RETURN coll # NIL
- END IsParsed;
- PROCEDURE GetIdElement(CONST name, id: ARRAY OF CHAR): Element;
- VAR contents: Objects.Enumerator; p: ANY; retElement: Element;
- BEGIN
- retElement := NIL;
- IF IsParsed() THEN
- contents := GetContents();
- WHILE contents.HasMoreElements() & (retElement = NIL) DO
- p := contents.GetNext();
- IF p IS Element THEN
- retElement := p(Element).GetIdElement(name, id)
- ELSIF p IS ExternalEntityRef THEN
- retElement := p(ExternalEntityRef).GetIdElement(name, id)
- END
- END
- END;
- RETURN retElement
- END GetIdElement;
- END ExternalEntityRef;
- TYPE
- Chars* = OBJECT (Content)
- PROCEDURE GetStr*(): String;
- BEGIN
- RETURN NIL
- END GetStr;
- PROCEDURE GetLength*(): LONGINT;
- BEGIN
- RETURN 0
- END GetLength;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR s: String;
- BEGIN
- s := GetStr(); w.String(s^)
- END Write;
- END Chars;
- TYPE
- ArrayChars* = OBJECT (Chars)
- VAR
- str: String;
- len: LONGINT;
- PROCEDURE &Init*;
- BEGIN
- str := NIL;
- len := 0;
- END Init;
- PROCEDURE GetStr*(): String;
- BEGIN
- RETURN str
- END GetStr;
- PROCEDURE GetLength*(): LONGINT;
- BEGIN
- RETURN len
- END GetLength;
- PROCEDURE SetStr*(CONST str: ARRAY OF CHAR);
- BEGIN
- SELF.str := NewString(str);
- len := DynamicStrings.StringLength(str)
- END SetStr;
- PROCEDURE SetStrAsString*(str : String);
- BEGIN
- SELF.str := str;
- len := DynamicStrings.StringLength(str^)
- END SetStrAsString;
- END ArrayChars;
- Comment* = OBJECT (ArrayChars)
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- NewLine(w, level-1); w.String("<!--"); Write^(w, context, level); w.String("-->"); NewLine(w, level)
- END Write;
- END Comment;
- TYPE
- CDataSect* = OBJECT (ArrayChars)
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR s : String; i, j : LONGINT; buf : ARRAY 4 OF CHAR;
- BEGIN
- w.String("<![CDATA[");
- s := GetStr(); COPY(" ", buf);
- IF (LEN(s^) < 3) THEN
- w.String(s^);
- ELSE
- buf[1] := s^[0];
- buf[2] := s^[1]; i := 2;
- WHILE (i < LEN(s^)) DO
- buf[0] := buf[1];
- buf[1] := buf[2];
- buf[2] := s^[i];
- INC(i);
- IF (buf = "]]>") THEN
- w.String("]]]]><![CDATA[>");
- IF ((i+2) < LEN(s^)) THEN
- buf[1] := s^[i]; INC(i);
- buf[2] := s^[i]; INC(i);
- ELSE
- j := 0;
- WHILE (i < LEN(s^)) DO
- buf[j] := s^[i]; INC(i); INC(j);
- END;
- buf[j] := 0X;
- END;
- ELSIF (i < LEN(s^)) THEN w.Char(buf[0]); END;
- END;
- w.String(buf);
- END;
- w.String("]]>"); NewLine(w, level)
- END Write;
- END CDataSect;
- TYPE
- ProcessingInstruction* = OBJECT (Content)
- VAR
- target, instruction: String;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- target := NIL; instruction := NIL;
- END Init;
- PROCEDURE GetTarget*(): String;
- BEGIN
- RETURN target
- END GetTarget;
- PROCEDURE SetTarget*(CONST target: ARRAY OF CHAR);
- BEGIN
- SELF.target := NewString(target)
- END SetTarget;
- PROCEDURE GetInstruction*(): String;
- BEGIN
- RETURN instruction
- END GetInstruction;
- PROCEDURE SetInstruction*(CONST instruction: ARRAY OF CHAR);
- BEGIN
- SELF.instruction := NewString(instruction)
- END SetInstruction;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- w.String("<?"); w.String(target^); w.Char(Space);
- w.String(instruction^); w.String("?>"); NewLine(w, level)
- END Write;
- END ProcessingInstruction;
- TYPE
- Attribute* = OBJECT (NameContent)
- VAR
- value, elementName: String;
- document: Document;
- decl: AttributeDecl;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- value := NIL; elementName := NIL;
- document := NIL;
- decl := NIL;
- END Init;
- PROCEDURE SetDocument(document: Document; elementName: String);
- VAR dtd: DocTypeDecl; elementDecl: ElementDecl;
- BEGIN
- SELF.document := document;
- SELF.elementName := elementName;
- dtd := document.GetDocTypeDecl();
- IF dtd # NIL THEN
- elementDecl := dtd.GetElementDecl(elementName^);
- IF elementDecl # NIL THEN
- decl := elementDecl.GetAttributeDecl(name^);
- IF (decl # NIL) & ((value = NIL) OR ~IsAllowedValue(value^)) THEN
- value := decl.defaultValue
- END
- END
- END
- END SetDocument;
- PROCEDURE IsAllowedValue*(CONST value: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- IF decl = NIL THEN
- RETURN TRUE
- ELSE
- CASE decl.GetType() OF
- | CData: RETURN TRUE
- | Id: RETURN document.root.GetIdElement(elementName^, value) = NIL
- | IdRef: RETURN TRUE
- | IdRefs: RETURN TRUE
- | Entity: RETURN TRUE
- | Entities: RETURN TRUE
- | NmToken: RETURN TRUE
- | NmTokens: RETURN TRUE
- | Notation:
- RETURN decl.allowedValues.Get(value) # NIL
- | Enumeration:
- RETURN decl.allowedValues.Get(value) # NIL
- ELSE
- END
- END
- END IsAllowedValue;
- PROCEDURE GetValue*(): String;
- BEGIN
- RETURN value
- END GetValue;
- PROCEDURE SetValue*(CONST value: ARRAY OF CHAR);
- BEGIN
- IF IsAllowedValue(value) THEN
- SELF.value := NewString(value)
- END
- END SetValue;
- PROCEDURE SetValueAsString*(value : String);
- BEGIN
- ASSERT(value # NIL);
- IF IsAllowedValue(value^) THEN
- SELF.value := value;
- END;
- END SetValueAsString;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- BEGIN
- IF value = NIL THEN KernelLog.String("NIL attribute "); KernelLog.Ln; RETURN END;
- w.Char(Space); w.String(name^);
- IF Strings.ContainsChar(value^, '"', FALSE) THEN
- w.String("='"); w.String(value^); w.Char("'")
- ELSE
- w.String('="'); w.String(value^); w.Char('"')
- END;
- END Write;
- END Attribute;
- TraverseProc* = PROCEDURE {DELEGATE} (c: Content; data: ANY);
- TYPE
- Element* = OBJECT (Container)
- VAR
- root, parent : Element;
- name: String; (* { name # NIL } *)
- document: Document;
- attributes : Attribute;
- idAttribute: Attribute;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- root := NIL; parent := NIL;
- name := StrNoName;
- document := NIL; attributes := NIL;
- idAttribute := NIL;
- END Init;
- PROCEDURE AddContent*(content: Content);
- BEGIN
- ASSERT(content # NIL);
- AddContent^(content);
- IF (content IS Element) THEN
- WITH content: Element DO
- IF root # NIL THEN content.root := root ELSE content.root := SELF; END;
- content.parent := SELF;
- END;
- END;
- END AddContent;
- PROCEDURE RemoveContent*(content : Content);
- BEGIN
- (*ASSERT(content # NIL);*)
- IF content=NIL THEN RETURN END; (*PH 12/13: removing nothing is logically correct *)
- RemoveContent^(content);
- IF (content IS Element) THEN
- IF (content(Element).parent = SELF) THEN
- content(Element).parent := NIL;
- content(Element).root := NIL;
- END;
- END;
- END RemoveContent;
- PROCEDURE SetDocument(document: Document);
- VAR
- dtd: DocTypeDecl; elementDecl: ElementDecl;
- enum : Objects.Enumerator; c : Content; p: ANY; attribute: Attribute;
- BEGIN
- ASSERT(document # NIL);
- SELF.document := document;
- root := document.GetRoot();
- dtd := document.GetDocTypeDecl();
- IF dtd # NIL THEN
- elementDecl := dtd.GetElementDecl(name^);
- IF elementDecl # NIL THEN
- enum := elementDecl.GetAttributeDecls();
- WHILE enum.HasMoreElements() DO
- p := enum.GetNext();
- WITH p: AttributeDecl DO
- attribute := GetAttribute(p.name^);
- IF attribute # NIL THEN
- attribute.SetDocument(document, name);
- ELSE
- NEW(attribute);
- attribute.name := p.name;
- attribute.value := p.defaultValue;
- attribute.SetDocument(document, name);
- AddAttribute(attribute);
- END;
- IF p.type = Id THEN idAttribute := attribute END
- END
- END
- END
- END;
- c := GetFirst();
- WHILE (c # NIL) DO
- IF (c IS Element) THEN c(Element).SetDocument(document);
- ELSIF (c IS EntityRef) THEN c(EntityRef).SetDocument(document);
- END;
- c := GetNext(c);
- END;
- END SetDocument;
- PROCEDURE SetName*(CONST name: ARRAY OF CHAR);
- BEGIN
- SELF.name := NewString(name)
- END SetName;
- PROCEDURE SetNameAsString*(name : String);
- BEGIN
- ASSERT(name # NIL);
- SELF.name := name
- END SetNameAsString;
- PROCEDURE GetName*(): String;
- BEGIN
- ASSERT(name # NIL);
- RETURN name
- END GetName;
- PROCEDURE GetId*(): String;
- BEGIN
- IF idAttribute # NIL THEN RETURN idAttribute.value
- ELSE RETURN NIL
- END
- END GetId;
- PROCEDURE GetIdElement*(CONST name, id: ARRAY OF CHAR): Element;
- VAR contents: Objects.Enumerator; content: ANY; idString: String; retElement: Element;
- BEGIN
- retElement := NIL;
- IF SELF.name^ = name THEN
- idString := GetId();
- IF (idString # NIL) & (idString^ = id) THEN retElement := SELF END
- END;
- IF retElement = NIL THEN
- contents := GetContents();
- WHILE contents.HasMoreElements() & (retElement = NIL) DO
- content := contents.GetNext();
- IF content IS Element THEN
- retElement := content(Element).GetIdElement(name, id)
- ELSIF content IS ExternalEntityRef THEN
- retElement := content(ExternalEntityRef).GetIdElement(name, id)
- END
- END
- END;
- RETURN retElement
- END GetIdElement;
- PROCEDURE AddAttribute*(attribute : Attribute);
- VAR a : Attribute;
- BEGIN {EXCLUSIVE}
- ASSERT((attribute # NIL) & (attribute.next = NIL) & (attribute.name # NIL) & (attribute.name^ # ""));
- RemoveAttributeInternal(attribute.name^);
- IF (attributes = NIL) THEN
- attributes := attribute;
- ELSE
- a := attributes;
- WHILE (a.next # NIL) DO a := a.next (Attribute); END;
- a.next := attribute;
- END;
- END AddAttribute;
- PROCEDURE RemoveAttributeInternal(CONST name : ARRAY OF CHAR);
- VAR a : Attribute;
- BEGIN (* caller holds object lock *)
- IF (attributes # NIL) THEN
- IF (attributes.name^ = name) THEN
- IF (attributes.next = NIL) THEN attributes := NIL; ELSE attributes := attributes.next (Attribute); END;
- ELSE
- a := attributes;
- WHILE (a.next # NIL) & (a.next(Attribute).name^ # name) DO a := a.next (Attribute); END;
- IF (a.next # NIL) THEN
- a.next := a.next.next;
- END;
- END;
- END;
- END RemoveAttributeInternal;
- PROCEDURE RemoveAttribute*(CONST name: ARRAY OF CHAR);
- BEGIN {EXCLUSIVE}
- RemoveAttributeInternal(name);
- END RemoveAttribute;
- PROCEDURE SetAttributeValue*(CONST name, value: ARRAY OF CHAR);
- VAR attribute: Attribute;
- BEGIN
- NEW(attribute); attribute.SetName(name); attribute.SetValue(value); AddAttribute(attribute)
- END SetAttributeValue;
- PROCEDURE GetAttribute*(CONST name: ARRAY OF CHAR): Attribute;
- VAR a : Attribute;
- BEGIN {EXCLUSIVE}
- a := attributes;
- WHILE (a # NIL) & (a.name^ # name) DO
- IF (a.next = NIL) THEN a := NIL; ELSE a := a.next (Attribute); END;
- END;
- RETURN a;
- END GetAttribute;
- PROCEDURE GetAttributeValue*(CONST name: ARRAY OF CHAR): String;
- VAR a : Attribute;
- BEGIN
- a := GetAttribute(name);
- IF (a # NIL) THEN
- RETURN a.GetValue();
- ELSE
- RETURN NIL;
- END;
- END GetAttributeValue;
- PROCEDURE GetAttributes*(): Objects.Enumerator;
- VAR a : Attribute; array : Objects.PTRArray; enumerator : Objects.ArrayEnumerator; i, nofAttributes : LONGINT;
- BEGIN {EXCLUSIVE}
- nofAttributes := 0;
- a := attributes;
- WHILE (a # NIL) DO
- INC(nofAttributes);
- IF (a.next # NIL) THEN a := a.next (Attribute); ELSE a := NIL; END;
- END;
- NEW(array, nofAttributes);
- a := attributes; i := 0;
- WHILE (a # NIL) DO
- array[i] := a; INC(i);
- IF (a.next # NIL) THEN a := a.next (Attribute); ELSE a := NIL; END;
- END;
- NEW(enumerator, array);
- RETURN enumerator;
- END GetAttributes;
- PROCEDURE HasAttribute*(CONST name : ARRAY OF CHAR) : BOOLEAN;
- BEGIN
- RETURN GetAttribute(name) # NIL;
- END HasAttribute;
- PROCEDURE GetRoot*(): Element;
- BEGIN
- RETURN root
- END GetRoot;
- PROCEDURE GetParent*(): Element;
- BEGIN
- RETURN parent
- END GetParent;
- PROCEDURE GetFirstChild*() : Element;
- VAR c : Content;
- BEGIN
- c := GetFirst();
- WHILE (c # NIL) & ~(c IS Element) DO
- c := GetNext(c);
- END;
- IF (c # NIL) THEN
- RETURN c(Element);
- ELSE
- RETURN NIL;
- END;
- END GetFirstChild;
- PROCEDURE GetNextSibling*(): Element;
- VAR c : Content;
- BEGIN
- c := next;
- WHILE (c # NIL) & ~(c IS Element) DO c := c.next; END;
- IF (c # NIL) THEN
- RETURN c(Element);
- ELSE
- RETURN NIL;
- END;
- END GetNextSibling;
- PROCEDURE GetPreviousSibling*() : Element;
- VAR c : Content;
- BEGIN
- c := previous;
- WHILE (c # NIL) & ~(c IS Element) DO c := c.previous; END;
- IF (c # NIL) THEN
- RETURN c(Element);
- ELSE
- RETURN NIL;
- END;
- END GetPreviousSibling;
- PROCEDURE Traverse*(traverseProc: TraverseProc; data: ANY);
- VAR c : Content;
- BEGIN
- ASSERT(traverseProc # NIL);
- traverseProc(SELF, data);
- c := GetFirst();
- WHILE (c # NIL) DO
- IF (c IS Element) THEN c(Element).Traverse(traverseProc, data);
- ELSE traverseProc(c, data);
- END;
- c := GetNext(c);
- END;
- END Traverse;
- PROCEDURE WriteAttributes*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR a : Attribute;
- BEGIN {EXCLUSIVE}
- a := attributes;
- WHILE (a # NIL) DO
- a.Write(w, context, level + 1);
- IF (a.next # NIL) THEN
- a := a.next (Attribute);
- ELSE
- a := NIL;
- END;
- END;
- END WriteAttributes;
- PROCEDURE Write*(w: Streams.Writer; context: ANY; level : LONGINT);
- VAR c : Content;
- BEGIN
- w.Char('<'); w.String(name^);
- WriteAttributes(w, context, level);
- c := GetFirst();
- IF (c = NIL) THEN w.String("/>")
- ELSE
- w.Char('>');
- IF ~(c IS ArrayChars) THEN NewLine(w, level + 1) END;
- c.Write(w, context, level + 1);
- WHILE (GetNext(c) # NIL) DO c := GetNext(c); NewLine(w, level + 1); c.Write(w, context, level + 1); END;
- IF ~(c IS ArrayChars) THEN NewLine(w, level); END;
- w.String("</"); w.String(name^); w.Char('>');
- END;
- END Write;
- END Element;
- TYPE
- GeneratorProcedure* = PROCEDURE(): Element;
- ElementEntry* = OBJECT
- VAR
- name- : ARRAY 32 OF CHAR;
- generator-: GeneratorProcedure;
- generatorModule-, generatorProcedure- : Modules.Name;
- PROCEDURE &Init*;
- BEGIN
- generator := NIL;
- COPY("", generatorModule); COPY("", generatorProcedure);
- END Init;
- END ElementEntry;
- ElementArray* = POINTER TO ARRAY OF ElementEntry;
- TYPE
- ElementRegistry* = OBJECT
- VAR
- generators: Objects.Dictionary;
- timestamp : LONGINT;
- PROCEDURE &Init*;
- VAR arrDict: Objects.ArrayDict;
- BEGIN
- NEW(arrDict); generators := arrDict;
- timestamp := 0;
- END Init;
- PROCEDURE RegisterElement*(CONST name: ARRAY OF CHAR; generator: GeneratorProcedure);
- VAR e: ElementEntry; p: ANY;
- BEGIN
- ASSERT(generator # NIL);
- p := generators.Get(name);
- IF p = NIL THEN
- NEW(e); COPY(name, e.name); e.generator := generator; generators.Add(name, e)
- ELSE (* redefinition *)
- p(ElementEntry).generator := generator
- END;
- INC(timestamp);
- END RegisterElement;
- PROCEDURE RegisterElementByName*(CONST name: ARRAY OF CHAR; CONST generatorModule, generatorProcedure: Modules.Name);
- VAR e: ElementEntry; p: ANY;
- BEGIN
- ASSERT((generatorModule # "") & (generatorProcedure # ""));
- p := generators.Get(name);
- IF p = NIL THEN
- NEW(e);
- COPY(name, e.name);
- e.generatorModule := generatorModule;
- e.generatorProcedure := generatorProcedure;
- generators.Add(name, e)
- ELSE (* redefinition *)
- p(ElementEntry).generatorModule := generatorModule;
- p(ElementEntry).generatorProcedure := generatorProcedure;
- END;
- INC(timestamp);
- END RegisterElementByName;
- PROCEDURE UnregisterElement*(CONST name: ARRAY OF CHAR);
- BEGIN
- generators.Remove(name);
- INC(timestamp);
- END UnregisterElement;
- PROCEDURE InstantiateElement*(CONST name: ARRAY OF CHAR): Element;
- VAR element : Element; entry : ElementEntry; p: ANY; generator : GeneratorProcedure;
- BEGIN
- element := NIL;
- p := generators.Get(name);
- IF (p # NIL) THEN entry := p (ElementEntry); END;
- IF (entry # NIL) THEN
- IF entry.generator # NIL THEN
- element := entry.generator();
- ELSE
- GETPROCEDURE(entry.generatorModule, entry.generatorProcedure, generator);
- IF (generator # NIL) THEN
- element := generator();
- ELSE
- KernelLog.String("Warning: XML.ElementRegistry.InstantiateElement: Factory procedure ");
- KernelLog.String(entry.generatorModule); KernelLog.String("."); KernelLog.String(entry.generatorProcedure);
- KernelLog.String(" not found."); KernelLog.Ln;
- END
- END
- END;
- RETURN element;
- END InstantiateElement;
- (** fof, late time instantiation to be able to react on generator properties *)
- PROCEDURE InstantiateLate*(e: Element): Element;
- BEGIN
- RETURN e (* stub *)
- END InstantiateLate;
- PROCEDURE GetTimestamp*() : LONGINT;
- BEGIN
- RETURN timestamp;
- END GetTimestamp;
- PROCEDURE GetElements*() : ElementArray;
- VAR enumerator : Objects.Enumerator; nofElements, i : LONGINT; ptr : ANY; ea : ElementArray;
- BEGIN
- enumerator := generators.GetEnumerator();
- nofElements := 0;
- WHILE enumerator.HasMoreElements() DO INC(nofElements); ptr := enumerator.GetNext(); END;
- IF (nofElements = 0) THEN
- ea := NIL;
- ELSE
- NEW(ea, nofElements);
- enumerator.Reset;
- i := 0;
- WHILE (i < nofElements) & enumerator.HasMoreElements() DO
- ptr := enumerator.GetNext();
- IF (ptr # NIL) & (ptr IS ElementEntry) THEN
- ea[i] := ptr (ElementEntry);
- ELSE
- ea[i] := NIL;
- END;
- INC(i);
- END;
- END;
- RETURN ea;
- END GetElements;
- END ElementRegistry;
- VAR
- StrNoName : Strings.String;
- (** Write an 0X-terminated UTF8 string to a stream (excl. 0X). XML special characters are escaped.
- Also works for ASCII strings. *)
- PROCEDURE UTF8ToStream*(CONST string : ARRAY OF CHAR; w : Streams.Writer; VAR res : WORD);
- VAR codeLength, stringLength, i : LONGINT; ch : CHAR;
- BEGIN
- ASSERT(w # NIL);
- res := Ok;
- stringLength := LEN(string);
- i := 0;
- WHILE (res = Ok) & (i < stringLength) & (string[i] # 0X) DO
- ch := string[i];
- codeLength := ORD(UTF8Strings.CodeLength[ORD(ch)]);
- IF (codeLength = 1) THEN
- CASE ch OF
- |'&': w.String("&");
- |'<': w.String("<");
- |'>': w.String(">");
- |'"': w.String(""");
- |"'": w.String("'");
- ELSE
- w.Char(ch);
- END;
- ELSIF (codeLength > 0) & (i + codeLength <= stringLength) THEN
- w.Bytes(string, i, codeLength);
- ELSE
- res := InvalidString;
- END;
- INC(i, codeLength);
- END;
- IF (i >= stringLength) OR (string[i] # 0X) THEN
- res := InvalidString;
- END;
- END UTF8ToStream;
- (** Read an UTF8 string from a stream and undo escaping of XML special characters. If the string array is to small, the string
- will be truncated and an error will be reported. <string> is always a valid 0X-terminated string.
- Also works for ASCII strings. *)
- PROCEDURE UTF8FromStream*(VAR string : ARRAY OF CHAR; r : Streams.Reader; VAR res : WORD);
- VAR ch : CHAR; escapeBuffer : ARRAY 8 OF CHAR; escaping : BOOLEAN; escapeIdx, codeLength, stringLength, i, len, actLen : LONGINT;
- PROCEDURE FlushEscapeBuffer;
- VAR j : LONGINT;
- BEGIN
- IF escaping THEN
- j := 0;
- WHILE (i < stringLength - 1) & (escapeBuffer[j] # 0X) DO
- string[i] := escapeBuffer[j];
- INC(i); INC(j);
- END;
- IF (escapeBuffer[j] # 0X) THEN res := BufferError; END;
- escaping := FALSE;
- END;
- END FlushEscapeBuffer;
- PROCEDURE CheckEscapeBuffer;
- BEGIN
- ASSERT(i < stringLength);
- IF (escapeIdx = 4) THEN
- IF (escapeBuffer = "<") THEN string[i] := "<"; INC(i); escaping := FALSE;
- ELSIF (escapeBuffer = ">") THEN string[i] := ">"; INC(i); escaping := FALSE;
- END;
- ELSIF (escapeIdx = 5) & (escapeBuffer = "&") THEN
- string[i] := "&"; INC(i); escaping := FALSE;
- ELSIF (escapeIdx = 6) THEN
- IF (escapeBuffer = """) THEN string[i] := '"'; INC(i); escaping := FALSE;
- ELSIF (escapeBuffer = "'") THEN string[i] := "'"; INC(i); escaping := FALSE;
- END;
- ELSIF (escapeIdx > 6) THEN
- FlushEscapeBuffer;
- END;
- END CheckEscapeBuffer;
- BEGIN
- ASSERT((r # NIL) & (LEN(string) >= 1));
- res := Ok;
- escaping := FALSE;
- stringLength := LEN(string);
- i := 0;
- ch := r.Peek();
- WHILE (res = Ok) & (ch # 0X) & (i < stringLength - 1) DO
- codeLength := ORD(UTF8Strings.CodeLength[ORD(ch)]);
- IF (codeLength = 1) THEN
- ch := r.Get();
- IF (ch = "&") THEN
- FlushEscapeBuffer;
- escaping := TRUE;
- escapeBuffer[0] := ch;
- escapeBuffer[1] := 0X;
- escapeIdx := 1;
- ELSIF escaping THEN
- escapeBuffer[escapeIdx] := ch;
- escapeBuffer[escapeIdx + 1] := 0X;
- INC(escapeIdx);
- CheckEscapeBuffer;
- ELSE
- string[i] := ch;
- INC(i);
- END;
- ELSIF (codeLength > 0) THEN
- FlushEscapeBuffer;
- len := MIN(codeLength, stringLength - 1 - i);
- IF (len > 0) THEN
- r.Bytes(string, i, len, actLen);
- IF (actLen # len) THEN
- res := InvalidString;
- ELSIF (len # codeLength) THEN
- res := BufferError;
- END;
- INC(i, actLen);
- ELSE
- res := BufferError;
- END;
- ELSE
- res := InvalidString;
- END;
- ch := r.Peek();
- END;
- string[i] := 0X;
- END UTF8FromStream;
- PROCEDURE NewLine(w : Streams.Writer; level : LONGINT);
- BEGIN
- w.Ln; WHILE level > 0 DO w.Char(Tab); DEC(level) END
- END NewLine;
- PROCEDURE NewString(CONST value: ARRAY OF CHAR): String;
- VAR s: String;
- BEGIN
- NEW(s, DynamicStrings.StringLength(value) + 1);
- COPY(value, s^);
- RETURN s
- END NewString;
- BEGIN
- StrNoName := Strings.NewString("");
- END XML.
|