FLAM Issue Tracker - FL5
View Issue Details
0000869FL52.2 Subprogram FLUC (CONV)public2017-03-26 22:542022-03-09 10:41
Falk Reichbott 
Falk Reichbott 
normalfeatureN/A
assignedopen 
GeneralGeneralGeneral
5.1.14 
5.1.30 
0000869: StAX like XML parser and writer
Mit der Version 5.1.15, welche wir gerade fertig stellen, kommen die
Integer- und Float-Element-Konverter, damit man FL5-XML-Elemente direkt
in Cobol-Zahlen-Datentypen (BCD und BIN) wandeln kann. Dies brauchen wir in de 5.1.16 für den Table-Support, damit sie CSV-Dateien als FB-Record über die Satzschnittstelle zurückbekommen oder auch schreiben können.

Wenn man auf der anderen Seite im XML weiß, dass ein Betrag jetzt
gekommen ist, dann konvertiert man das Attributevalue oder das
Datenelement zu einem BCD oder 2'er-Komplement.

Da das XML-Element ein UTF-8-String ist, muss man also die Zahl von
einer externen Stringdarstellung in die interne neutrale Zahlendarstellung
 (wir nutzen BCD, damit es keinen Genauigkeitsverlust gibt) überführen und von
  dieser in den jeweiligen externen Datentyp, welchen man in seinem COPYBOOK braucht
   (egal, wie die Zahl in dem XML-Dokument gestanden hat).

> "conv.integer(from(format.str(chrset=UTF8)) to(format.bin(width=32)))"

Hierfür haben wir den FROM-TO-Conversion-String (siehe oben und die komplette
Syntax am Ende der Mail) eingeführt und stellen mit der 5.1.15 alle Konvertrierung
 auch explizit über die neue Funktion FCRCONV(hdl,rtc,inlen, indat,outlen, outdat)
  zur Verfügung. Manchmal
weis man beim GET halt noch nicht, welche die richtige implitzite
Konvertierung wäre. In solchen Fällen oder halt immer kann man explizit
konvertieren. Haben Sie hier noch Ideen oder Wünsche.

Jetzt ist noch der Umgang mit unsere FL5-Element-Struktur beim
format.element() an sich zu komplex und man könnte für die Kunden auf
Basis des FLUC-Element-API im Gegensatz zum COBOL XML PARSE (SAX
(Callback/Eventhandler-API)) eine vereinfachte XMLPULL-API anbieten (StAX).

hdl=FCXOPEN(filstr,modstr)
Man gibt beim Open nur den READ.XML-String mit und über den Mode-String
legt man fest, ob man die simple oder die komplexe Varinate und noch so
ein paar Kleinigkeiten (Case-Senitive oder nicht, CCSID im Speicher, Selection (ENUM) für XML-Schlüsselwörter, und vieles mehr) haben will.

vsn=FCXGVSN(hdl)
enc=FCXGENC(hdl)
Nach dem Open kann man die XML-Version und das Encoding abfragen, da der
optionale XML-Tag ggf. schon weggelesen wurde.

R15=FCXNEXT(hdl)
Die Next-Funktion liest das nächste XML-Element und gibt den
Element-Type (Token>0) oder halt einen Fehler (Token<0, kann EOF sein)
zurück (sie stellt den Scanner für die diversen Datenformate (SEPA) in XML dar).

In Abhängigkeit des Typ bzw. Tokens kann man sich nun mit diversen
GET-Funktionen, die jeweiligen Datentypen an dieser Cursor-Position
abholen. Hierbei gibt es für XML-Schlüsselwörter (Tag-Namen und
Attribut-Namen) zwei Varianten. GetKeyWord (FCXGKW) gibt den String zum
Vergleich zurück (Case sensitive oder in Großbuchstaben) oder wenn man
eine Selection im Open definiert hat, dann gibt GetKeyValue (FCXGKV) den
INTEGER (PIC 9(9) COMP) für das Schlüsselwort zurück, sofern es gefunden
wurde (Achtung, bezieht sich auf den Tag- oder Attribut-Namen).

R15=FCXGKW(hdl,kywlen,kyw)
R15=FCXGKV(hdl)

In Abhängigkeit des Types/Token kann man ein XML-Schlüsselwort und oder
XML-Daten abfragen (State-Maschine im Hintergrund zur kontrolle). Zum Beispiel
kann man beim Token XML-ATTRIBUTE sich das KeyWord/Value oder die Daten geben lassen.
Bei der Datenabfrage kann man sich die internen UTF-8-Strings in jegliche Datentypen wandeln
lassen. Für jeden Datentyp gibt es entsprechende GET-Funktionen.

R15=FCXGSV(hdl) - GetSelectionValue
Wandelt auch ein Schlüsselwort (Attributevalue oder Datenteil) in eine
Zahl (Fullword)

R15=FCXGBH(hdl,binlen,bindat) - GetBinHex
Wandelt hexadezimalen String in Binärdaten.

R15=FCXGB6(hdl,binlen,bindat) - GetBinB64
Wandelt Base64 String in Binärdaten (mit oder ohne Armor-Header-Trailer).

R15=FCXGIB(hdl,intlen,intdat) - GetIntBin
Wandelt Zahlenstring in 2'Complement der Längen 1, 2, 4 und 8

R15=FCXGIC(hdl,bcdlen,bcddat) - GetIntBcd
Wandelt Zahlenstring gepackten BCD mit Vorzeichen

R15=FCXGFB(hdl,fltlen,fltdat) - GetFltBin
Wandelt Zahlenstring in binären Float der Längen 4, 8 und 16

R15=FCXGFCxx(hdl,fltlen,fltdat) - GetFltBcd
Wandelt Zahlenstring in BCD Float, wobei xx für die Nachkommastellen
steht und die fltlen die führenden Nullen ergibt

R15=FCXGSC(hdl,strlen,strdat) - GetStrClp (Collapsed)
Gibt String collapsed zurück

R15=FCXGSB(hdl,strlen,strdat) - GetStrBth (Both)
Gibt String ohne Trailing and leading Whitespace zurück

R15=FCXGDAT(hdl,datlen,data) - GatData
Gibt die Daten unverändert (UTF-8) zurück.

Da wird es noch einiges mehr an Funktionen geben, hier nur mal die
Wichtigsten, um das Prizip zu veranschaulichen.

Nun noch zu den Varianten:

Simple:

Hier gibt es die folgenden XML-Typen/Token, DTD, Processing-Instructions und Kommentare werden
überlesen. CDATA wird nicht akzeptiert. Datenteile dürfen eine
Stringlänge von 64k nicht übersteigen (kann im Open verkleinert oder bis
zu 1GiB vergrößert werden). Datenteile sind nur in den Blättern möglich.
Datenteile einfach zwischen drin, dürfen nur Whitespace enthalten und
werden genauso wie Default-Elemente überlesen. Sprich eine klassische
XML-Datei ohne Spakazien (ggf. kann Simple auch CDATA, aber da CDATA
auch Datenteile unterbrechen kann, passt dies nicht wirklich, man könnte an sich nur XML_ENDSTARTELMCDATA noch einführen, sprich ein ganzes Datenelement muss CDATA sein.)

> XML-STARTELM hier geht kann man sich nur das Key-Word/Value holen
> XML-ATTRIBUTE hier kann man sich Key-Word/Value und die Daten holen
> XML-ENDSTARTELM hier kommen keine Daten und man kann sich nur das KeyWord/Value holen
> XML-ENDSTARTELMDATA hier kann man sich die Daten und das KeyWord/Value holen
> XML-ENDELM hier kann man sich nur das KeyWord/Value holen

Das XML-Dokument darf bei der simplen Variante nur folgende Syntax haben (bitte beachten, dass DTD, Default-Elemente, leere Datenelemente und Kommentar überlesen werden).

> xml-document -> XML-TAG xml-statement-list
> | xml-statement-list
>
> xml-statement-list -> xml-statement xml-statement-list
> | @
>
> xml-statement -> XML-STARTELM xml-attr-list XML-ENDELM
> | XML-STARTELM xml-attr-list XML-ENDSTARTELMDAT
> | XML-STARTELM xml-attr-list XML-ENDSTARTELM xml-statement-list XML-ENDELM
>
> xml-attr-list -> XML-ATTRIBUTE xml-attr-list
> | @

Das XML-ENDSTARTELMDAT kennzeichnet ein Blatt mit Daten und der CloseTag
(XML-ENDELM) wurde schon mit Weggelesen (um das Ende der Daten zu
bestimmen), sprich es kommt kein XML-ENDELM für ein Blatt sondern nur
wenn es ein XML-ENDSTARTELM ohne Daten, dafür mit weiteren XML-STARTELM (nächste Hierarchiestufe) gegeben hat.

Die optionale "xml-attr-list" könnte man noch eleminieren, indem man sie durch
 GetAttrCount (FCXGAC oder FCXNEXT gibt im oberen Halbword, den Attribut-Count
  gleich mit zurück) und weitere Getter (FirstAttr, NextAttr, LastAttr, FindAttr, ...)
   ersetzt, womit man immer das gesamte XML-Tag als Cursor-Position hätte.

> xml-statement -> XML-ATTRELM
> | XML-DATAELM
> | XML-CDATAELM
> | XML-STARTELM xml-statement-list XML-ENDELM

Da der Open schon das "xml-document" abarbeitet, hätte man so mit 3 Funktionen seinen kompletten XML-Parser fertig.

> int tag;
>
> match(hdl,typ) {
> if (tag==typ) {
> return(FCXNEXT(hdl));
> } else {
> error(syntax);
> }
> }
>
> main() {
> hdl=FCXOPEN("read(file='DD:INPUT')","mode.simple()");
> tag=FCXNEXT(hdl);
> xml_statement_list(hdl);
> }
>
> xml_statement_list(hdl) {
> while(tag=XML-ATTRELM || XML-DATAELM || tag==XML-STARTELM) {
> xml_statement(hdl);
> }
> }
>
> xml_statment(hdl) {
> switch(tag) {
> case XML-ATTRELM:
> FCXGKW(hdl,kywlen,kywdat);
> ...
> tag=match(hdl,XML-ATTRELM);
> break;
> case XML-DATAELM:
> FCXGKW(hdl,kywlen,kywdat);
> ...
> tag=match(hdl,XML-DATAELM);
> break;
> case XML_STARTELM:
> FCXGKW(hdl,kywlen,kywdat);
> ...
> tag=match(hdl,XML_STARTELM);
> xml_statement_list(hdl);
> tag=match(hdl,XML_ENDELM);
> break;
> default:
> error();
> break;
> }

Komplex (ohne DTD, müsste aber dabei sein):

> xml-document -> XML-TAG xml-statement-list
> | xml-statement-list
>
> xml-statement-list -> xml-statement xml-statement-list
> | @
>
> xml-statement -> XML-STARTELM xml-list XML-ENDELM
> | XML-COMMENT
>
> xml-list -> xml-element xml-list
> | @
>
> xml-element -> xml-statement
> | xml-cdata-statement
> | XML-DATA
> | XML-PROCINS
> | XML-DEFAULTS
>
> xml-cdata-statement -> XML-START-CD xml-data-list XML-END-CD
>
> xml-data-list -> XML-DATA xml-data-list
> | @

Die komplexe Variante unterstützt dann CDATA, Kommentare, Datenteile
überall und auch mehrteilige Datenpasagen (größer 64k) und DTD. Allerding gibt es dann wieder alle Elementtypen und in der Regel kann man sich bis auf die Attribute entweder die KeyWords/Values oder die Daten abholen.

Das Schreiben geht an sich genauso (simple oder complex), nur das man hier mit Settern
 die Daten an das Handle übergibt und dann mit FCXNEXT() das Rausschreiben bewirkt. Beim
  Lesen wird es noch das FCXPREV() geben, womit man den Cursor um ein Element zurückbewegen
   kann.
No tags attached.
Issue History
2017-03-26 22:54Falk ReichbottNew Issue
2017-03-26 22:54Falk ReichbottStatusnew => assigned
2017-03-26 22:54Falk ReichbottAssigned To => Falk Reichbott
2017-03-27 10:45Falk ReichbottDescription Updatedbug_revision_view_page.php?rev_id=362#r362
2017-05-02 11:52Falk ReichbottDescription Updatedbug_revision_view_page.php?rev_id=363#r363
2017-05-02 11:53Falk ReichbottNote Added: 0001098
2017-05-02 11:55Falk ReichbottNote Added: 0001099
2017-08-31 16:52Falk ReichbottTarget Version5.1.16 => 5.1.18
2017-11-10 09:41Falk ReichbottTarget Version5.1.18 => 5.1.19
2018-06-22 16:49Falk ReichbottTarget Version5.1.19 => 5.1.23
2019-12-05 10:36Falk ReichbottTarget Version5.1.23 => 5.1.28
2021-04-30 12:03Falk ReichbottTarget Version5.1.28 => 5.1.29
2022-03-09 10:41Falk ReichbottTarget Version5.1.29 => 5.1.30

Notes
(0001098)
Falk Reichbott   
2017-05-02 11:53   
CONV.{
--| ? BINARY(
--|--| ? FROM(
--|--|--| ? DECODE=BASE16/BASE32/BASE64
--|--|--| ? CHRSET=NONE/SYSTEM/ASCII/UCS1/UTF8/EBCDIC/UCS2BE/UTF16BE/UCS2LE/UTF16LE/UCS4BE/UTF32BE/UCS4LE/UTF32LE
--|--|--| ? IGNSPC)
--|--| ? TO(
--|--|--| ? ENCODE=BASE16/BASE32/BASE64
--|--|--| ? CHRSET=NONE/SYSTEM/ASCII/UCS1/UTF8/EBCDIC/UCS2BE/UTF16BE/UCS2LE/UTF16LE/UCS4BE/UTF32BE/UCS4LE/UTF32LE))
--| ? STRING(
--|--| ? FROM(
--|--|--| ? CHRSET(
--|--|--|--| ? CCSID='str'/DEFAULT/ASCII/EBCDIC
--|--|--|--| ? CASE=UPPER/LOWER/FOLD/SUPPER/SLOWER/USRTAB
--|--|--|--| ? USRTABLE='str'/NPAS/SEPA/DELA/DLAX
--|--|--|--| ? WHITESPACE=PRESERVE/REPLACE/COLLAPSE/REMOVE/TRAILING/LEADING/BOTH/NUMBER))
--|--| ? TO(
--|--|--| ? CHRSET(
--|--|--|--| ? CCSID='str'/DEFAULT/ASCII/EBCDIC
--|--|--|--| ? CASE=UPPER/LOWER/FOLD/SUPPER/SLOWER/USRTAB
--|--|--|--| ? MODE=STOP/IGNORE/SUBSTITUTE
--|--|--|--| ? SUBCHAR[num/SYSTEM...]
--|--|--|--| ? SYSTABLE=ICONV
--|--|--|--| ? USRTABLE='str'/NPAS/SEPA/DELA/DLAX
--|--|--|--| ? WHITESPACE=PRESERVE/REPLACE/COLLAPSE/REMOVE/TRAILING/LEADING/BOTH/NUMBER)
--|--|--| ? NUMBER(
--|--|--|--| ! FORMAT='str'
--|--|--|--| ? LOCALE='str'
--|--|--|--| ? MINIMUM='str'
--|--|--|--| ? MAXIMUM='str'
--|--|--|--| ? MININCL
--|--|--|--| ? MAXINCL
--|--|--|--| ? IGNREST
--|--|--|--| ? BASE=num/BIN/B02/OCT/B08/DEC/B10/HEX/B16)
--|--|--| ? MODE=STOP/CUT
--|--|--| ? FIXEDLENGTH=num
--|--|--| ? PADDING=NONE/RIGHT/LEFT
--|--|--| ? PADCHAR='bin'/BINARY-ZERO/ASCII-BLANK/EBCDIC-BLANK/UTF08-BLANK/UTF16BE-BLANK/UTF16LE-BLANK/UTF32BE-BLANK/UTF32LE-BLANK
--|--|--| ? NULLTERM))
--| ? INTEGER(
--|--| ? FROM(
--|--|--| ? FORMAT.{
--|--|--|--| ? BIN(
--|--|--|--|--| ? SIGNED
--|--|--|--|--| ? ENDIAN=SYSTEM/BIG/LITTLE)
--|--|--|--| ? BCD(
--|--|--|--|--| ? SIGNED
--|--|--|--|--| ? TYPE=UNPACKED/PACKED/ZONED
--|--|--|--|--| ? ZONE=SYSTEM/ASCII/EBCDIC)
--|--|--|--| ? STR(
--|--|--|--|--| ? CHRSET=NONE/SYSTEM/ASCII/UCS1/UTF8/EBCDIC/UCS2BE/UTF16BE/UCS2LE/UTF16LE/UCS4BE/UTF32BE/UCS4LE/UTF32LE
--|--|--|--|--| ? BASE=num/BIN/B02/OCT/B08/DEC/B10/HEX/B16
--|--|--|--|--| ? WHITESPACE=PRESERVE/REPLACE/COLLAPSE/REMOVE/TRAILING/LEADING/BOTH/NUMBER)})
--|--| ? TO(
--|--|--| ? FORMAT.{
--|--|--|--| ? BIN(
--|--|--|--|--| ? SIGNED
--|--|--|--|--| ? ENDIAN=SYSTEM/BIG/LITTLE
--|--|--|--|--| ? WIDTH=num/W08/W16/W32/W64)
--|--|--|--| ? BCD(
--|--|--|--|--| ? SIGNED
--|--|--|--|--| ? TYPE=UNPACKED/PACKED/ZONED
--|--|--|--|--| ? ZONE=SYSTEM/ASCII/EBCDIC
--|--|--|--|--| ? DIGITS=num)
--|--|--|--| ? STR(
--|--|--|--|--| ? CHRSET=NONE/SYSTEM/ASCII/UCS1/UTF8/EBCDIC/UCS2BE/UTF16BE/UCS2LE/UTF16LE/UCS4BE/UTF32BE/UCS4LE/UTF32LE
--|--|--|--|--| ? BASE=num/BIN/B02/OCT/B08/DEC/B10/HEX/B16
--|--|--|--|--| ? DIGITS=num
--|--|--|--|--| ? SIGN=IFNEGATIVE/SPACEIFPOSITIVE/PLUSIFPOSITIVE
--|--|--|--|--| ? CASE=UPPER/LOWER
--|--|--|--|--| ? FIXEDLENGTH=num
--|--|--|--|--| ? PADDING=NONE/RIGHT/LEFT
--|--|--|--|--| ? PADCHAR='bin'/BINARY-ZERO/ASCII-BLANK/EBCDIC-BLANK/UTF08-BLANK/UTF16BE-BLANK/UTF16LE-BLANK/UTF32BE-BLANK/UTF32LE-BLANK
--|--|--|--|--| ? NULLTERM)}))
--| ? FLOAT(
--|--| ? FROM(
--|--|--| ? FORMAT.{
--|--|--|--| ? BIN(
--|--|--|--|--| ? TYPE=num/SYSTEM
--|--|--|--|--| ? ENDIAN=SYSTEM/BIG/LITTLE)
--|--|--|--| ? BCD(
--|--|--|--|--| ? SIGNED
--|--|--|--|--| ? TYPE=UNPACKED/ZONED
--|--|--|--|--| ? ZONE=SYSTEM/ASCII/EBCDIC
--|--|--|--|--| ? FRACDIGITS=num)
--|--|--|--| ? STR(
--|--|--|--|--| ? CHRSET=NONE/SYSTEM/ASCII/UCS1/UTF8/EBCDIC/UCS2BE/UTF16BE/UCS2LE/UTF16LE/UCS4BE/UTF32BE/UCS4LE/UTF32LE
--|--|--|--|--| ? WHITESPACE=PRESERVE/REPLACE/COLLAPSE/REMOVE/TRAILING/LEADING/BOTH/NUMBER
--|--|--|--|--| ? SEPARATOR=SYSTEM/PERIOD/COMMA)})
--|--| ? TO(
--|--|--| ? FORMAT.{
--|--|--|--| ? BIN(
--|--|--|--|--| ? TYPE=num/SYSTEM
--|--|--|--|--| ? ENDIAN=SYSTEM/BIG/LITTLE
--|--|--|--|--| ? WIDTH=num/W32/W64)
--|--|--|--| ? BCD(
--|--|--|--|--| ? SIGNED
--|--|--|--|--| ? TYPE=UNPACKED/ZONED
--|--|--|--|--| ? ZONE=SYSTEM/ASCII/EBCDIC
--|--|--|--|--| ? INTDIGITS=num
--|--|--|--|--| ? FRACDIGITS=num)
--|--|--|--| ? STR(
--|--|--|--|--| ? CHRSET=NONE/SYSTEM/ASCII/UCS1/UTF8/EBCDIC/UCS2BE/UTF16BE/UCS2LE/UTF16LE/UCS4BE/UTF32BE/UCS4LE/UTF32LE
--|--|--|--|--| ? SIGN=IFNEGATIVE/SPACEIFPOSITIVE/PLUSIFPOSITIVE
--|--|--|--|--| ? INTDIGITS=num
--|--|--|--|--| ? SEPARATOR=SYSTEM/PERIOD/COMMA
--|--|--|--|--| ? FRACDIGITS=num
--|--|--|--|--| ? FIXEDLENGTH=num
--|--|--|--|--| ? PADDING=NONE/RIGHT/LEFT
--|--|--|--|--| ? PADCHAR='bin'/BINARY-ZERO/ASCII-BLANK/EBCDIC-BLANK/UTF08-BLANK/UTF16BE-BLANK/UTF16LE-BLANK/UTF32BE-BLANK/UTF32LE-BLANK
--|--|--|--|--| ? NULLTERM)}))}
(0001099)
Falk Reichbott   
2017-05-02 11:55   
Erste API-Definition für C, Lademodulinterface dann später analog.

#define FCX_SIMPLE_ATTRELM 0x00000000
#define FCX_SIMPLE_DATAELM 0x00010000
#define FCX_SIMPLE_CDATELM 0x00020000
#define FCX_SIMPLE_STARTELM 0x00030000
#define FCX_SIMPLE_ENDELM 0x00040000

#define FCX_COMPLEX_COMMENT 0x00010000
#define FCX_COMPLEX_DEFAULT 0x00020000
#define FCX_COMPLEX_DATAELM 0x00030000
#define FCX_COMPLEX_PROCINS 0x00040000
#define FCX_COMPLEX_STARTELM 0x00050000
#define FCX_COMPLEX_ENDELM 0x00060000
#define FCX_COMPLEX_CDSTART 0x00070000
#define FCX_COMPLEX_CDEND 0x00080000

extern void* fcxopen(const char* filstr, const char* fmtstr);
extern int fcxconvbin(void* hdl, const char* cnvstr);
extern int fcxconvint(void* hdl, const char* cnvstr);
extern int fcxconvflt(void* hdl, const char* cnvstr);
extern int fcxconvstr(void* hdl, const char* cnvstr);
extern int fcxnexttag(void* hdl, char** kyw, int* tag);
extern int fcxgetdata(void* hdl, int* len, void* dat, const int cnv);
extern int fcxnextatr(void* hdl, char** kyw, int* tag);
extern int fcxgetattr(void* hdl, int* len, void* dat, const int cnv);
extern int fcxgetnsuri(void *hdl);
extern int fcxgetnsprefix(void *hdl);
extern int fcxclose(void* hdl);