version=1.4.2 vdate=18.06.2020 fname=jsf.cls ns=%NAMESPACE% fpath=/vba/classes ====== [VBA] JSF ====== //Daten aus Tabellen in Text parsen// ==Version %%version%% %%vdate%%== >//Das Modul hat versteckte Attribute. Damit diese aktiv übernommen werden reicht es nicht aus, den Code in ein neues Modul zu kopieren. Man muss das Modul aus der Datei nach VBA importieren.// >{{popup>:vba:vba_importfile.png|Bild zum Import}} {{%%fname%%|Download %%fname%% (V-%%version%%)}} Es war schon immer mein Traum, Daten aus Einer Tabelle oder Abfrage relativ einfach in ein Text zu parsen. Mit der Klasse JSF habe ich mir diesen Traum umgesetzt. Im Prinzip ist es einfach. In einem Text können mit dem Pattern #{[inhalt]} Daten aus einer Tabelle oder eines Dictionary ausgelesen werden. Zudem kann darin jeder VBA-Code verwendet werden, der durch eval() ausgewertet werden kann. pattern = "Willkommen #{user}. Es ist jetzt #{TimeValue(now())} und du bist seit #{DateDiff('d', start_date, now)} Tagen dabei." ?JSF("T_JSF_EXAMPLE").parse(pattern) Willkommen Stefan. Es ist jetzt 12:51:41 und du bist seit 39 Tagen dabei. ===== Definition ===== ==== Bedingte Komplilierung / Settings ==== Es gibt 2 Bedingte Komplilierungen. Je nachdem, ob die Module geladen sind oder nicht. Im Zweifelsfall beide auf False stellen. Man hat dann einfach ein bischen weniger möglichkeiten == sPrintF_exists == [[vba:functions:printf:index|]] ' /** ' * Wenn sprintf existiert, dann kann mit $format das Format analog zu sprintf() mitgegeben werden. Ansonsten wird der $-Teil ignoriert ' * @url http://wiki.yaslaw.info/doku.php/vba/functions/printf/index ' * @example ?JSF().parse("#{now $To}") -> 20181109 ' * @example ?JSF().parse("#{1.3 $.3f}") -> 1.300 ' * @example ?JSF("DUAL").parse("#{now $TO}_#{id $6d}_DATA.CSV") -> 20181109_092806_000001_DATA.CSV ' */ #Const sPrintF_exists = True == json_exists == [[vba:cast:json|]] '/** ' * Wenn mein json-Modul vorhanden ist, dann kann man auch json-Strings als Paramter übergeben. ' * Achtung! Nur eindimensionale Dictionary! ' * @url http://wiki.yaslaw.info/doku.php/vba/cast/json ' * @example ?JSF("{nr:1,name:Yaslaw}").parse("#{name}, du hast die Nummer #{nr} ") -> Yaslaw, du hast die Nummer 1 ' */ #Const json_exists = True ==== Methoden ==== === Initialisierungs-Methoden === == instance() == '/** ' * Erstellt ein neues Objekt und initialisiert es ' * @param Dictionary/Recordset/TableDef/QueryDef/Iterator/Sql/TableName/QueryName/ ' * @param String Einen Filter umd auf den richtigen Datensatz zu springen. Nur gültig für Recordset, TableDef und ähnliches ' * @param jsfParams Paramter um die Klasse zu steuern ' * @return JSF ' */ Public Function instance( _ Optional ByRef iSource As Variant = Nothing, _ Optional ByVal iCriteria As String, _ Optional ByVal iParams As jsfParams = jsfParams.[_Default] _ ) As JSF == construct() == '/** ' * Initialisiert ein JSF-Objekt ' * @param Dictionary/Recordset/TableDef/QueryDef/Iterator/Sql/TableName/QueryName/ ' * @param String Einen Filter umd auf den richtigen Datensatz zu springen. Nur gültig für Recordset, TableDef und ähnliches ' * @param jsfParams Paramter um die Klasse zu steuern ' * @return JSF ' */ Public Function construct( _ Optional ByRef iSource As Variant = Nothing, _ Optional ByVal iCriteria As String, _ Optional ByVal iParams As jsfParams = jsfParams.[_Default] _ ) As JSF === Methoden === == parse() == '/** ' * Parst einen Text mit den vorhandenen Daten ' * @param String ' * @return String ' */ Public Function parse(ByVal iString As String) As String == add() == '/** ' * Fügt ein Wert der Map zu oder überschreibt ihn ' * @param String Key ' * @param Variant Value ' * @return JSF ' */ Public Function add(ByVal iKey As String, ByVal iValue As Variant) As JSF === Source === Die folgenden Quellen sind zulässig * Dictionary * Recordset * TableDef * QueryDef * Iterator * Sql (Select-Statement) * TableName * QueryName * JSON-String (für ein eindimensioneles Dictionary und nur wenn das JSON-Modul installiert ist und die bedingte Komplilierung json_exists auf True gesetzt ist) ==== Modifiers ==== Ab Version 1.3 gibt es Modifiers, mit denen man die Werte belästigen kann. \\ Die grundsätzliche Syntax ist ''value|modifier:param1:param2:...:paramX''. Der Modifier wird mit einem ''|'' angehäng, gefolgt von den Paramtern, die mit '':'' getrennt werden Es können mehrere Modifier auf ein Element angewendet werden. Sie werden in der angegeben Reihenfolge abgearbeitet. ''value|modifier1:param11|modifier2|modifier2:param31''. ^ Modifier ^ Atribute ^ Beschreibung / VBA-Befehl ^ Beispiel ^ | format | $format | VBA.format(wert, $format) | ''%%|%%format:'0.00''' | | trim | | VBA.Trim(wert) | ''%%|%%trim'' | | rev | | VBA.StrReverse(wert) | ''%%|%%rev'' | | lcase | | VBA.LCase(wert) | ''%%|%%lcase'' | | lower | | Alais zu lcase | ''%%|%%lower'' | | ucase | | VBA.UCase(wert) | ''%%|%%ucase'' | | upper | | Alais zu ucase | ''%%|%%upper'' | | proper | | VBA.strConv(wert, vbProperCase) | ''%%|%%proper'' | | strconv | $convType als Integer | VBA.strConv(wert, $convType) | ''%%|%%strconv:3'' | | tech | | Falls cast_techName im Projekt vorhanden ist, wird dieses ausgeführt. techName(wert) | ''%%|%%tech'' | | nz | $default=Leerstring | VBA.nz(wert, $default) \\ nz funktioniert auch, wenn das Element nicht in der Liste existiert | ''%%|%%nz \\ %%|%%nz:'NA''' | | round | $size=0 | VBA.round(wert, $size) | ''%%|%%round:2'' | | sql | | wandelt den Wert in ein SQL-Wert | ''%%|%%sql'' | | code | | Alias zu sql | ''%%|%%code'' | | reg_replace | $pattern, $replace | Führt ein RegEx-Replace durch | ''%%|%%reg_replace:'\d(\w+)':'$1''' | | rxr | $pattern, $replace | Alias zu reg_replace | ''%%|%%rxr:'\d(\w+)':'$1''' | | lpad | $len, $padString = ' ' | Links mit Zeichen auffüllen | ''%%|%%lpad:3'' \\ ''%%|%%lpad:3:'_''' | | rpad | $len, $padString = ' ' | Rechts mit Zeichen auffüllen | ''%%|%%rpad:3'' \\ ''%%|%%rpad:3:'_''' | | item | $key/$index, $defaultKey=null | Wählt aus einer Unterliste den entsprechenden Wert | ''%%|%%item:3'' | tbl | $range = Leerstring | Erstellt eine ADODB-Excel-tabelle [tblname$range] | ''%%|%%Sheet1'' \\ ''%%|%%Sheet1:'A1:A3''' | | fld | $table | Erstellt ein SQL-String für ein Feld oder ein Tabelle. | ''%%|%%fld'' \\ ''%%|%%fld:table'' | \\ ''%%|%%item:ort'' \\ ''%%|%%item:ort:unbekannt'' | ? jsf("{name:Yaslaw, ort:null, sex:null}") _ .parse("#{sex|nz:m='m' ? 'Herr' : 'Frau'} #{name|upper} aus #{ort|nz:unbekannt|proper}") Herr YASLAW aus Unbekannt 'sex ist in der Tabelle gar nicht enthalten, wird jedoch mit nz gesetzt ? jsf("{name:Yaslaw, ort:null}").parse("#{sex|nz:'männlich'}") männlich 'b ist wieder ein Dictionary d Jsf("{a:A,b:{name:Hans,ort:Winterthur}}").parse(" #{b|item:name} aus #{b|item:1}") 'Hans aus Winterthur' Set j = Jsf("{flag:ort,data:{name:Hans,ort:Winterthur,flag:test,country:Schweiz}}") 'Das Attribut flag ist nit in ' gefasst. Also wird versucht auch dieses zu paren. flag hat somit den Wert ort d j.parse("#{data|item:flag}") 'Winterthur' 'Setzen wir flag hingegen in '', dann wird der Wert flag genommen um in der Unterliste zu suchen d j.parse("#{data|item:'flag'}") 'test' 'Land ist in der Liste nicht vorhanden d j.parse("#{data|item:'land'}") '' d j.parse("#{data|item:'land':'country'}") 'Schweiz' 'fld und tpl Set j = jsf("{t1:table_1,t2:[table_2],f1:'[ort]', f2:PLZ}") d j.map ( [t1] => 'table_1' [t2] => 'table_2' [f1] => '[ort]' [f2] => 'PLZ' ) ?j.parse("select #{f1|fld:a}, #{f2|fld|upper} from #{t1|tbl:'A1:F4'} a, #{t2|tbl} b") select [a].[ort], [PLZ] from [table_1$A1:F4] a, [table_2$] b ===== Anwendungsbeipiele ===== Meine Tabelle mit den Testdaten ^ Tabelle T_JSF_EXAMPLE ^^^^^^ ^ ID ^ USER ^ VULGO ^ LOCATION ^ START_DATE ^ IS_IMPORTANT ^ | 1 | Stefan | Yaslaw | Büro 1A | 01.10.2018 | True | | 2 | Sandra | | Büro 3 | 01.11.2018 | False | | 3 | Manuela | Manu | Home | 29.10.2018 | False | | 4 | Thomas | | | 31.10.2018 | True | ==== Einfache Beispiele ==== 'Einfaches auslesen des ersten Datensatzes der Tabelle und parsen der Daten ? JSF("T_JSF_EXAMPLE").parse("Welcome #{user}") Welcome Stefan 'Mit einer VBA-Funktion. In diesem Beispiel nz() ? JSF("T_JSF_EXAMPLE").parse("Welcome #{nz(vulgo, user)}") Welcome Yaslaw 'dasselbe mit einem Datenkriterium ? JSF("T_JSF_EXAMPLE", "id=2").parse("Welcome #{nz(vulgo, user)}") Welcome Sandra 'mit einem if - Schreibweise (criteria ? true) ? JSF("T_JSF_EXAMPLE", "id=1").parse("Welcome #{user}#{is_important ? '!'}") Welcome Stefan! ? JSF("T_JSF_EXAMPLE", "id=2").parse("Welcome #{user}#{is_important ? '!'}") Welcome Sandra 'und einem else - Schreibweise (criteria ? true : false) ? JSF("T_JSF_EXAMPLE", "id=2").parse("Welcome #{user}#{is_important ? '!' : '.'}") Welcome Sandra. 'Ein Not in Form eines ! ?JSF("T_JSF_EXAMPLE").parse("#{user} hat #{!IsNull(LOCATION) ? 'ein' : 'kein'} Arbeitsplatz") Stefan hat ein Arbeitsplatz ?JSF("T_JSF_EXAMPLE").parse("#{user} ist #{user != 'Sandra' ? 'nicht '}Sandra") Stefan ist nicht Sandra === Mit Array als Quelle === Auch ein Array kann eine Quelle sein. Dann wird der Key als ''[index]'' gehandhabt. Es beginnt also mit ''[0]'' ? JSF(array("Yaslaw","Winterthur","Herr")).parse("Hallo #{[2]} #{[0]} aus #{[1]}") Hallo Herr Yaslaw aus Winterthur ==== Beispiele mit Funktionen ==== === User defined Function mit Recordset === Public Function test(ByVal iUserId As Long, ByVal iHutgroesse As Long) As String Dim rs As DAO.Recordset Dim parser As New JSF Set rs = CurrentDb.openRecordset("SELECT * FROM T_JSF_EXAMPLE WHERE ID=" & iUserId) parser.construct rs 'Noch einen eigenen Wert mitgeben parser.add "HutGr", iHutgroesse test = parser.parse("#{user} hat die Hutgrösse #{hutgr}") End Function 'Und der Test: ?test(3, 57) Manuela hat die Hutgrösse 57 Und als Vergleich als Einzeiler ?JSF("T_JSF_EXAMPLE", "ID=3").add("HutGr", 57).parse("#{user} hat die Hutgrösse #{hutgr}") Manuela hat die Hutgrösse 57 === User defined Function mit Dictionary === Public Function test() As String Dim dict As New Dictionary Dim parseer As JSF 'Das Dictionary kähme natürlich woanders her. dict.add "Ort", "Winterthur" dict.add "PLZ", "8404" Set parser = JSF(dict) test = parser.parse("Willkommen in #{plz} #{ort}") End Function ?test Willkommen in 8404 Winterthur === In einem SQL === Man kann über einen kleinen Kniff die Klasse auch in einem SQL verwenden. Aber achtung, ist nicht sehr perfomant! Als Erstes muss man noch eine Funktion schreiben, da man nicht direkt auf das Objekt zugreifen kann. Zum Beispiel Public Function DJsf(ByVal iSource As String, Optional ByVal iCriteria As String, Optional ByVal iPattern As String) As String DJsf = JSF(iSource, iCriteria).parse(iPattern) End Function Und hier mein Test Die Daten code]SELECT * FROM T_VALUES; ID | VORNAME | NACHNAME ---|---------|--------- 1 | Hans | Muster 2 | Heidi | Knobel 3 | Sandra | Test SELECT * FROM T_PATTERNS; ID | PATTERN ---|---------------------------------- 1 | Person #{VORNAME} #{NACHNAME} 2 | #{NACHNAME}, #{VORNAME} ist Toll! Und das SQL SELECT v.*, djsf('T_VALUES', 'ID=' & v.id, p.pattern) AS txt FROM T_VALUES v, T_PATTERNS p; ID | VORNAME | NACHNAME | txt ---|---------|----------|------------------------ 1 | Hans | Muster | Person Hans Muster 1 | Hans | Muster | Muster, Hans ist Toll! 2 | Heidi | Knobel | Person Heidi Knobel 2 | Heidi | Knobel | Knobel, Heidi ist Toll! 3 | Sandra | Test | Person Sandra Test 3 | Sandra | Test | Test, Sandra ist Toll! === Beispiele mit Modifiers === ==== Beipiele mit den Zusatzfunktionen ==== === sprintf() === [[#sPrintF_exists]] Für die Formatierungen, schaue direkt bei [[vba:functions:printf:index#sprintf() mit Formatierungen|]] ?JSF("T_JSF_EXAMPLE").parse("Hallo #{user} es ist #{now() $TT}") Hallo Stefan es ist 12:12:55 'Ein User-file ohne Formatierung ?JSF("select * from T_JSF_EXAMPLE where id=4").parse("#{now()}_UID#{id}_USER_REPORT.CSV") 09.11.2018 12:16:15_UID4_USER_REPORT.CSV 'und mit Formatierung über sprintf ?JSF("select * from T_JSF_EXAMPLE where id=4").parse("#{now() $TO}_UID#{id $3d}_USER_REPORT.CSV") 20181109_121538_UID004_USER_REPORT.CSV 'und dasselbe ohne sprintf mit Standard VBA Befehlen ?JSF("select * from T_JSF_EXAMPLE where id=4").parse("#{format(now(), 'YYYYMMDD_HHNNSS')}_UID#{String('0', 3-len(id)) & id}_USER_REPORT.CSV") 20181109_121830_UID4_USER_REPORT.CSV === JSON === [[#json_exists]] Das Beispiel macht so nicht direkt Sinn. Erst in Komplexen Applikationen kann es vereinzelt Sinn ergeben. ?JSF("{ort:Winterthur,PLZ:8404}").parse("Willkommen in #{plz} #{ort}") Willkommen in 8404 Winterthur ===== Code ===== {{%%fname%%|Download %%fname%% (V-%%version%%)}}