FLAM Issue Tracker - FL5 | |||||
View Issue Details | |||||
ID | Project | Category | View Status | Date Submitted | Last Update |
0000869 | FL5 | 2.2 Subprogram FLUC (CONV) | public | 2017-03-26 22:54 | 2022-03-09 10:41 |
Reporter | Falk Reichbott | ||||
Assigned To | Falk Reichbott | ||||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | assigned | Resolution | open | ||
Platform | General | OS | General | OS Version | General |
Product Version | 5.1.14 | ||||
Target Version | 5.1.30 | Fixed in Version | |||
Summary | 0000869: StAX like XML parser and writer | ||||
Description | 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. | ||||
Steps To Reproduce | |||||
Additional Information | |||||
Tags | No tags attached. | ||||
Relationships | |||||
Attached Files | |||||
Issue History | |||||
Date Modified | Username | Field | Change | ||
2017-03-26 22:54 | Falk Reichbott | New Issue | |||
2017-03-26 22:54 | Falk Reichbott | Status | new => assigned | ||
2017-03-26 22:54 | Falk Reichbott | Assigned To | => Falk Reichbott | ||
2017-03-27 10:45 | Falk Reichbott | Description Updated | bug_revision_view_page.php?rev_id=362#r362 | ||
2017-05-02 11:52 | Falk Reichbott | Description Updated | bug_revision_view_page.php?rev_id=363#r363 | ||
2017-05-02 11:53 | Falk Reichbott | Note Added: 0001098 | |||
2017-05-02 11:55 | Falk Reichbott | Note Added: 0001099 | |||
2017-08-31 16:52 | Falk Reichbott | Target Version | 5.1.16 => 5.1.18 | ||
2017-11-10 09:41 | Falk Reichbott | Target Version | 5.1.18 => 5.1.19 | ||
2018-06-22 16:49 | Falk Reichbott | Target Version | 5.1.19 => 5.1.23 | ||
2019-12-05 10:36 | Falk Reichbott | Target Version | 5.1.23 => 5.1.28 | ||
2021-04-30 12:03 | Falk Reichbott | Target Version | 5.1.28 => 5.1.29 | ||
2022-03-09 10:41 | Falk Reichbott | Target Version | 5.1.29 => 5.1.30 |
Notes | |||||
|
|||||
|
|
||||
|
|||||
|
|