All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sta.cts.JSONScanner Maven / Gradle / Ivy


package com.sta.cts;

import java.io.IOException;
import java.io.StringReader;
import java.util.Date;
import java.util.Hashtable;

import com.sta.mlogger.MLogger;

/**
 * 

Name: JSONScanner

*

Description: . *

*

Comment: ... *

*

Copyright: Copyright (c) 2018, 2019, 2021

*

Company: >StA-Soft<

* @author StA * @version 1.0 */ public class JSONScanner extends Scanner { // private static final String NULL_MAGIC = "___NULL_MAGIC___"; /** * Im JSON-Scanner verwendete Symbole. */ public enum JSONSym { /** * Array-Anfang ("["). */ ARRAY_BEGIN, /** * Array-Ende ("]"). */ ARRAY_END, /** * Object-Anfang ("{"). */ OBJECT_BEGIN, /** * Object-Ende ("}"). */ OBJECT_END, /** * Doppelpunkt (":"). */ COLON, /** * Komma (","). */ COMMA, /** * Null ("null"). */ NULL } /** * Operations-Level f?r JSON-Bl?tter. */ protected int myLevel = 0; /** * Aktuell zu verwendende JSON-Blatt-Hash-Tabelle. */ protected LeafHashtable myLHT = null; //=========================================================================== /** * Standard-Constructor. */ public JSONScanner() { } //=========================================================================== @Override public void initH(Hashtable pHT) { // preOverread(); // siehe: init(is, enc) } //--------------------------------------------------------------------------- /** * ?berlie?t Spaces incl. #$09, #$0d, #$0a. Bei anderen Zeichen erfolgt ein * Abbruch. Das entscheidende Zeichen wird gelesen und zur?ckgeliefert. * @return letztes und entscheidendes Zeichen * @throws IOException falls ein Lesefehler auftritt */ protected char overreadSpaces() throws IOException { char ch; do { ch = getChar(); } while ((ch == ' ') || (ch == 0x09) || (ch == 0x0d) || (ch == 0x0a)); return ch; } /** * Zeichenkette parsen. Trennzeichen am Anfang muss bereits gelesen sein. * Abschlie?endes Trennzeichen wird ?berlesen. * @return Text f?r Zeichenkette (Inhalt zwischen Trennzeichen) * @throws IOException im Fehlerfall */ private String scanString() throws IOException { StringBuilder sb = new StringBuilder(); boolean ex = false; while (!ex) { char ch = getChar(); if (ch == 0x00) { MLogger.wrn("Missing end of String."); ex = true; } else if (ch == '\"') { // ungetChar(ch); ex = true; } else if (ch == '\\') { char ch1 = getChar(); if (ch1 == '\\') { sb.append(ch1); } else if (ch1 == '\"') { sb.append(ch1); } else if (ch1 == '/') { sb.append(ch1); } else if (ch1 == 'b') { sb.append('\b'); } else if (ch1 == 'f') { sb.append('\f'); } else if (ch1 == 'n') { sb.append('\n'); } else if (ch1 == 'r') { sb.append('\r'); } else if (ch1 == 't') { sb.append('\t'); } else if (ch1 == 'u') { StringBuilder sb1 = new StringBuilder(); for (int i = 0; i < 4; i++) { ch1 = getChar(); if (((ch1 >= '0') && (ch1 <= '9')) || ((ch1 >= 'a') && (ch1 <= 'f')) || ((ch1 >= 'A') && (ch1 <= 'F'))) { sb1.append(ch1); } else { throw new IOException("Invalid \\u combination: " + sb.toString() + ch1); } } int ic = Integer.valueOf(sb1.toString(), 16); sb.append((char) ic); } else { MLogger.wrn("Invalid character in mask sequence: " + ch1); ungetChar(ch1); ex = true; } } else { sb.append(ch); } } return sb.toString(); } /** * Schl?sselwort scannen. * @return Schl?sselwort * @throws IOException im Fehlerfall */ private String scanKeyWord() throws IOException { StringBuilder sb = new StringBuilder(); boolean ex = false; while (!ex) { char ch = getChar(); if (ch == 0x00) { ex = true; } else if ((ch >= 'a') && (ch <= 'z')) { sb.append(ch); } else { ungetChar(ch); ex = true; } } return sb.toString(); } /** * Zahl (Integer/Long und/oder Float/Double) scannen. * @return Number * @throws IOException im Fehlerfall */ private Number scanNumber() throws IOException { StringBuilder sb = new StringBuilder(); boolean isIntLong = true; boolean ex = false; while (!ex) { char ch = getChar(); if (ch == 0x00) { ex = true; } else if ((ch >= '0') && (ch <= '9')) { sb.append(ch); } else if ((ch == '+') || (ch == '-')) { sb.append(ch); } else if ((ch == '.') || (ch == 'E')) { sb.append(ch); isIntLong = false; } else { ungetChar(ch); ex = true; } } String s = sb.toString(); if (s.length() > 0) { if (isIntLong) { Long v = UniTypeConv.convString2Long(s); return ((v <= Integer.MAX_VALUE) && (v >= Integer.MIN_VALUE)) ? v.intValue() : v; } else { return UniTypeConv.convString2Double(s); } } return null; } @Override public Object getNewToken() { Object token = null; try { boolean ex = false; while (!ex) { char ch = overreadSpaces(); if (ch == 0x00) { ex = true; } else if (ch == '[') { token = JSONSym.ARRAY_BEGIN; ex = true; } else if (ch == ']') { token = JSONSym.ARRAY_END; ex = true; } else if (ch == '{') { token = JSONSym.OBJECT_BEGIN; ex = true; } else if (ch == '}') { token = JSONSym.OBJECT_END; ex = true; } else if (ch == ':') { token = JSONSym.COLON; ex = true; } else if (ch == ',') { token = JSONSym.COMMA; ex = true; } else if (ch == '\"') { token = scanString(); ex = true; } else if ((ch >= '0') && (ch <= '9')) { ungetChar(ch); token = scanNumber(); ex = true; } else if ((ch >= 'a') && (ch <= 'z')) { ungetChar(ch); String s = scanKeyWord(); if ("true".equals(s)) { return true; } else if ("false".equals(s)) { return false; } else if ("null".equals(s)) { return JSONSym.NULL; } else { MLogger.wrn("Invalid key word: " + s); return s; } } else { MLogger.wrn("Unknown character: " + ch); } } } catch (IOException e) { } return token; } /** * Pr?fen, ob ein bestimmtes Symbol folgt, und falls ja: ?berlesen. * @param sym Symbol * @return true: ja, Symbol gefunden, Symbol wurde ?berlesen, false: nein, anderes Symbol, Symbol wurde nicht ?berlesen */ public boolean check(JSONSym sym) { Object token = getToken(); if (token != sym) { ungetToken(token); return false; } return true; } /** * Es wird gepr?ft, ob ein Blatt mit dem angegebenen Namen folgt. Falls ja, werden Name, ":" und Wert gelesen, ein optional * folgendes "," ?berlesen und der Wert zur?ckgegeben. Falls nein, wird der Name zur?ckgelegt und null zur?ckgeliefert. * @param pName Name/Schl?ssel des Blatts * @return Wert des Blatts, falls vorhanden, sonst null * @throws Exception im Fehlerfall */ public Object getLeaf(String pName) throws Exception { Object token = getToken(); if ((token instanceof String) && (token.equals(pName))) { token = getToken(); if (token == JSONSym.COLON) { token = getToken(); if (token == null) { return null; } else if (token instanceof String) { check(JSONSym.COMMA); return token; } else if (token instanceof Number) { check(JSONSym.COMMA); return token; } else if (token instanceof Boolean) { check(JSONSym.COMMA); return token; } else if (token == JSONSym.NULL) { check(JSONSym.COMMA); return null; } else { MLogger.wrn("Invalid value: " + token); } } else { ungetToken(token); throw new Exception("Missing \":\", found: " + token); } } else { ungetToken(token); } return null; } /** * String-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als String * @throws Exception siehe getLeaf */ public String getLeafString(String pName) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof String) { return (String) obj; } throw new Exception("Invalid leaf type. Expected: String, found: " + obj); } /** * Integer-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Integer * @throws Exception siehe getLeaf */ public Integer getLeafInt(String pName) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof Integer) { return (Integer) obj; } if (obj instanceof Long) { return ((Long) obj).intValue(); } throw new Exception("Invalid leaf type. Expected: Integer, found: " + obj); } /** * Long-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Long * @throws Exception siehe getLeaf */ public Long getLeafLong(String pName) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof Long) { return (Long) obj; } if (obj instanceof Integer) { return ((Integer) obj).longValue(); } throw new Exception("Invalid leaf type. Expected: Long, found: " + obj); } /** * Float-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Float * @throws Exception siehe getLeaf */ public Float getLeafFloat(String pName) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof Float) { return (Float) obj; } if (obj instanceof Double) { return ((Double) obj).floatValue(); } if (obj instanceof Integer) { return ((Integer) obj).floatValue(); } if (obj instanceof Long) { return ((Long) obj).floatValue(); } throw new Exception("Invalid leaf type. Expected: Float, found: " + obj); } /** * Double-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Double * @throws Exception siehe getLeaf */ public Double getLeafDouble(String pName) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof Double) { return (Double) obj; } if (obj instanceof Float) { return ((Float) obj).doubleValue(); } if (obj instanceof Integer) { return ((Integer) obj).doubleValue(); } if (obj instanceof Long) { return ((Long) obj).doubleValue(); } throw new Exception("Invalid leaf type. Expected: Double, found: " + obj); } /** * Date-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @param pMask optionale Maske * @return Inhalt als Date (nur Datum) * @throws Exception siehe getLeaf */ public Date getLeafDate(String pName, String pMask) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof String) { return UniTypeConv.convString2Date((String) obj, pMask); } throw new Exception("Invalid leaf type. Expected: String for Date, found: " + obj); } /** * Date-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Date (nur Datum) * @throws Exception siehe getLeaf */ public Date getLeafDate(String pName) throws Exception { return getLeafDate(pName, null); } /** * Time-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @param pMask optionale Maske * @return Inhalt als Date (nur Zeitangabe) * @throws Exception siehe getLeaf */ public Date getLeafTime(String pName, String pMask) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof String) { return UniTypeConv.convString2Time((String) obj, pMask); } throw new Exception("Invalid leaf type. Expected: String for Time, found: " + obj); } /** * Time-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Date (nur Zeitangabe) * @throws Exception siehe getLeaf */ public Date getLeafTime(String pName) throws Exception { return getLeafTime(pName, null); } /** * DateTime-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @param pMask optionale Maske * @return Inhalt als Date (Datum und Zeitangabe) * @throws Exception siehe getLeaf */ public Date getLeafDateTime(String pName, String pMask) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof String) { return UniTypeConv.convString2DateTime((String) obj, pMask); } throw new Exception("Invalid leaf type. Expected: String for DateTime, found: " + obj); } /** * DateTime-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Date (Datum und Zeitangabe) * @throws Exception siehe getLeaf */ public Date getLeafDateTime(String pName) throws Exception { return getLeafDateTime(pName, null); } /** * Boolean-JSON-Blatt lesen. * @param pName der Name des JSON-Blatt-Tags * @return Inhalt als Boolean * @throws Exception siehe getLeaf */ public Boolean getLeafBool(String pName) throws Exception { Object obj = getLeaf(pName); if (obj == null) { return null; } if (obj instanceof Boolean) { return (Boolean) obj; } throw new Exception("Invalid leaf type. Expected: Boolean, found: " + obj); } /** * myLevel erh?hen. */ public void incLevel() { myLevel++; } /** * myLevel verringern. */ public void decLevel() { myLevel--; } /** * Ermittlung der LeafHashtable, um z. B. zu pr?fen, ob diese nach Laden * eines TO's auch wirklich leer ist. * @return die LHT */ public LeafHashtable getLHT() { return myLHT; } /** * Spezielle Hashtabelle aus JSON-Bl?ttern erzeugen. * In der Hashtabelle liegen unter den JSON-Blatt(-Tag)-Namen (String) als * Schl?ssel der Wert des jeweiligen Blatts (ebenfalls als String). * Object-Anfang muss gelesen worden sein. Object-Ende wird nicht ?berlesen. * @return diese Hashtabelle * @throws Exception falls ein Lesefehler auftritt, ebenso im Falle von JSON-Struktur-Fehlern */ public LeafHashtable getLeafs() throws Exception { if (myLevel != 0) { return myLHT; } myLHT = new LeafHashtable(); boolean cont = false; do { Object token = getToken(); if (!(token instanceof String)) { ungetToken(token); // Falls nach einem Blatt bereits ein "," gelesen wurde, dann MUSS ein neues Blatt (und somit ein String) kommen! // if (cont) // { // throw new Exception("JSON-Error 0 (missing name/key for leaf, found: " + (token != null ? token.toString() : "(null)") + ")"); // } break; } String name = (String) token; token = getToken(); if (token != JSONSym.COLON) { throw new Exception("JSON-Error 1 (missing colon ':' in leaf: " + name + ", found: " + (token != null ? token.toString() : "(null)") + ")"); } token = getToken(); String s = ""; if (token instanceof String) { s = (String) token; } else if (token instanceof Integer) { s = UniTypeConv.convInt2String((Integer) token); } else if (token instanceof Long) { s = UniTypeConv.convLong2String((Long) token); } else if (token instanceof Float) { s = UniTypeConv.convFloat2String((Float) token); } else if (token instanceof Double) { s = UniTypeConv.convDouble2String((Double) token); } else if (token instanceof Boolean) { s = UniTypeConv.convBool2String((Boolean) token); } else { throw new Exception("JSON-Error 2 (invalid value type in leaf: " + name + ", found: " + (token != null ? token.toString() : "(null)") + ")"); } myLHT.put(name, s); cont = check(JSONSym.COMMA); } while (cont); return myLHT; } /** * Pr?fen, ob die Leaf-Hash-Tabelle (LHT) leer ist, falls nicht: Meldungen (als Warnungen) ausgeben. * @param lht die LHT * @param text Text f?r die Meldung. */ public static void checkLHT(LeafHashtable lht, String text) { if ((lht != null) && !lht.isEmpty()) { lht.forEach((key, value) -> MLogger.wrn("LHT (" + text + ") not empty: " + "\"" + key + "\" : " + value)); /* Enumeration e = lht.keys(); while (e.hasMoreElements()) { String key = (String) e.nextElement(); String val = (String) lht.get(key); MLogger.wrn("LHT (" + text + ") not empty: " + "\"" + key + "\" : " + val); } */ MLogger.wrn("Please check JSON-Source-File!"); } } /** * Pr?fen, ob die Leaf-Hash-Tabelle (LHT) leer ist, falls nicht: Meldungen (als Warnungen) ausgeben, * Darf nur nach getLeafs() verwendet werden, bezieht sich auf das letzte getLeafs(). * @param text Text f?r die Meldung. */ public void checkLHT(String text) { checkLHT(myLHT, text); } //=========================================================================== /** * Main-Methode. * @param args Kommandozeilenargumente */ public static void main(String... args) { try { JSONScanner js = new JSONScanner(); String s = "\"Strg\" : \"Hallo!\", \"Strg1\" : \"Hallo1!\""; js.init(new StringReader(s)); Object obj = js.getLeaf("Strg"); MLogger.deb(() -> "obj: " + obj); Object obj1 = js.getLeaf("Strg1"); MLogger.deb(() -> "obj1: " + obj1); js.close(); s = "\"Strg\" : \"Hallo!\", \"Strg1\" : \"Hallo1!\", \"Int\" : \"0\", \"Int1\" : \"1\""; js.init(new StringReader(s)); LeafHashtable lht = js.getLeafs(); MLogger.deb(() -> "result: " + lht.toString()); MLogger.deb(() -> "lht-int-as-int: " + lht.getLeafInt("Int")); MLogger.deb(() -> "lht-int-as-string: " + lht.getLeafString("Int1")); js.checkLHT("test"); js.close(); } catch (Exception ex) { MLogger.err("", ex); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy