/
akolonin
/
aigents-java
Обзор
Документация
Войти
/
akolonin
/
aigents-java
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/main/java/net/webstructor/al/Writer.java
644 строки
19 KB
Anton Kolonin
3.4.8 JSON and Sentiment fixes
08 июл 2021, 07:45
08 июл 2021, 07:45
5a9d6f3
Код
Авторство
О чём код?
/* * MIT License * * Copyright (c) 2005-2020 by Anton Kolonin, Aigents® * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package net.webstructor.al; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.TreeSet; import net.webstructor.agent.Body; import net.webstructor.agent.Schema; import net.webstructor.core.Property; import net.webstructor.core.Thing; import net.webstructor.peer.Session; import net.webstructor.util.Str; import net.webstructor.cat.HtmlStripper; public class Writer extends AL { public Writer(Body body) { super(body); } public static String term(Object obj) { if (obj instanceof String) return (String)obj; return null; } public static String and(Set terms) { StringBuilder out = new StringBuilder(); for (int i=0, cnt=0;i<terms.size();i++) { String term = (String)term(terms.get(i)); if (term != null) { if (cnt++ > 0) out.append(',').append(' '); //out.append(term); toString(out,term); } } return out.toString(); } private static void toString(StringBuilder out,Thing thing, Object context) { toString(out, thing, context, null, false); } public static String toString(Thing thing, Object context, String[] names, boolean form) { StringBuilder sb = new StringBuilder(); toString(sb,thing,null,names,true); return sb.toString(); } public static void toString(StringBuilder out,Thing thing, Object context, String[] names, boolean form) { if (context != null) { //TODO: make unique reference AKA buildQualifier String ref = thing.getString(name); if (ref == null) ref = AL.there[0]; if (!AL.empty(ref)) toString(out,ref); } else { if (names == null) names = thing.getNamesAvailable(); if (names.length == 0) out.append(AL.no[0]); else { String[] sorted = new String[names.length]; for (int i=0, c=0;i<names.length;i++) { String name = (String)names[i]; Object value = thing.get(name); if (value != null) sorted[c++] = name + (form ? ": " : space) + toString(value,name); } Arrays.sort(sorted); for (int i=0, c=0;i<names.length;i++) { if (sorted[i] != null) { if (c++ > 0){ if (!form) out.append(',').append(space); else out.append('\n'); } out.append(sorted[i]); } } } } } public static String toString(Set set,String delimiters) { return toString(new StringBuilder(),set,delimiters,0).toString(); } public static StringBuilder toString(StringBuilder out,Set set,String delimiters,int level) { if (empty(set)) return out; if (!set.is()) out.append(negation); int size = set.size(); for (int i=0; i<size; i++) { if (i > 0) if (delimiters != null && level < delimiters.length()) out.append(delimiters.charAt(level)); else out.append(space); if (set.get(i) instanceof Set) toString(out,(Set)set.get(i),delimiters,level + 1); else toString(out,set.get(i),set); } return out; } public static StringBuilder toString(StringBuilder out,Set set,boolean strict) { if (empty(set)) return out; if (!set.is()) out.append(negation); int size = set.size(); if (size > 1 || strict) out.append(set instanceof Seq? '[' : set instanceof Any? '{' : '(' ); for (int i=0; i<size; i++) { if (i > 0) { if (!(set instanceof Seq)) { //out.append(',');//TODO:why do we thik we need comma here at all? } out.append(space); } toString(out,set.get(i),set); } if (size > 1 || strict) out.append( set instanceof Seq? ']' : set instanceof Any? '}' : ')' ); return out; } private static void toString(StringBuilder out,Collection coll) { if (empty(coll)) return; //recursion++; String[] sorted = new String[coll.size()]; //TODO: consider when brackets need to appear //if (coll.size() > 1) // out.append( '(' ); int c = 0; for (Iterator it = coll.iterator(); it.hasNext(); ) sorted[c++] = toString(it.next(),coll); Arrays.sort(sorted); for (int i=0;i<sorted.length;i++) { if (i > 0) out.append(',').append(space); out.append(sorted[i]); } //if (coll.size() > 1) // out.append( ')' ); //recursion--; } //TODO:more strict conditions of quoting other than ending with punctuation!? public static boolean needsQuoting(String string) { return needsQuoting(string,false);//ignore spaces } public static boolean needsQuoting(String string, boolean spaces) { if (AL.empty(string)) // or just if string.length() == 0 ? return true; if (string.charAt(0) == '#')//may be ID such as #123 return true; //boolean url = AL.isURL(string); int len_minus_1 = string.length() - 1; for (int i = 0; i <= len_minus_1; i++) { char ch = string.charAt(i); //http://stackoverflow.com/questions/7996919/should-url-be-case-sensitive //if (url && Character.isUpperCase(ch)) //TODO: understand impact on total quoting, say disability to do case-insentivie searches and comparisons if (Character.isUpperCase(ch)) return true; if (spaces && AL.spaces.indexOf(string.charAt(i)) != -1) return true; if (AL.punctuation.indexOf(ch) != -1) // if punctiation before the end or spaces if (!Parser.punctuationException(string,i,string.length(),AL.punctuation)) return true; if (AL.quotes.indexOf(ch) != -1) return true; //https://stackoverflow.com/questions/24840667/what-is-the-regex-to-extract-all-the-emojis-from-a-string if (Character.isSurrogate(ch) || (i < len_minus_1 && Character.isSurrogatePair(ch, string.charAt(i + 1)))) return true; } return false; } public static String quote(String string) { return quote(new StringBuilder(),string).toString(); } public static StringBuilder quotequotable(StringBuilder out, String string) { return needsQuoting(string,true) ? quote(out,string) : out.append(string); } public static StringBuilder quote(StringBuilder out, String string) { boolean singl = string.indexOf('\'') != -1; boolean doubl = string.indexOf('\"') != -1; char quote = singl ? '\"' : '\''; if (singl && doubl) { string = string.replace("\'", "\\\'"); string = string.replace("\"", "\\\""); } out.append(quote).append(string).append(quote); return out; } public static void toString(StringBuilder out,String string) { toString(out, string, false); } public static void toString(StringBuilder out,String string,boolean quoting) { if (string != null) { if (quoting || needsQuoting(string)) quote(out,string); else out.append(string); } } public static void toString(StringBuilder out,Object obj) { toString(out,obj,null); } public static void toString(StringBuilder out,Object obj,Object context) { if (obj instanceof Float) out.append(((Float)obj).floatValue()); else if (obj instanceof Double) out.append(((Float)obj).doubleValue()); else if (obj instanceof Boolean) out.append(((Boolean)obj).booleanValue()); else if (obj instanceof Integer) out.append(((Integer)obj).intValue()); else if (obj instanceof Number) out.append(((Number)obj).toString()); else if (obj instanceof String) //TODO:fix quotable hack! toString(out,(String)obj,needsQuoting((String)obj) || (context instanceof String && Schema.quotable((String)context))); else if (obj instanceof Property) out.append('$').append(((Property)obj).name()); else if (obj instanceof Thing) toString(out, (Thing) obj, context); else if (obj instanceof Collection) toString(out, (Collection)obj); else if (obj instanceof Set) toString(out, (Set)obj, false); else if (obj instanceof Object[]) toString(out, new All((Object[])obj)); else if (obj instanceof Ref) { Ref ref = (Ref)obj; if (!ref.is()) out.append(negation); toString(out, ref.get(0),context); } else if (obj instanceof Date) out.append(Time.day((Date)obj,true)); else out.append("<error>"); } private static String toString(Object obj,Object context) { StringBuilder out = new StringBuilder(); toString(out,obj,context); return out.toString(); } public static String toString(Object obj) { return toString(obj,null); } public static String toString(Object[] array,Object context) { return toString(array,context,"[",", ","]"); } public static String toString(Object[] array,Object context, String before, String middle, String after) { StringBuilder out = new StringBuilder(); if (!AL.empty(array)){ if (!AL.empty(before)) out.append(before); for (int i = 0; i < array.length; i++){ if (i > 0 && !AL.empty(middle)) out.append(middle); toString(out,array[i],context); } if (!AL.empty(after)) out.append(after); } return out.toString(); } public static String what(String ref,Thing thing,Set terms) { StringBuilder out = new StringBuilder(); out.append("what").append(' ').append(ref).append(' ').append(and(terms)).append('?'); return capitalize(out); } //TODO:sensible query-context-driven output formation public static String toPrefixedString(Session session, Seq query, Object arg) { Object head = AL.empty(query) ? null : query.get(0); String ref = head == null ? null : head instanceof Body? AL.i_my[0]: //TODO: get rid of this hack needed for agressive GC impact head instanceof Thing && session != null && head.equals(session.getBody().self())? AL.i_my[0]: head instanceof Thing && session != null && head.equals(session.getStoredPeer()) ? AL.you[0]: head instanceof Thing && session != null && session.getStoredPeer()==null ? AL.you[0]: //TODO: fix demo hack for anonymous users! head instanceof Thing && session != null && head.equals(session.getStoredPeer())? ((Thing)head).getString(name): head instanceof Seq && ((Seq)head).size()==2 && ((Seq)head).get(0).equals(AL.name)? ((Seq)head).get(1).toString(): AL.there[0]; if (query != null && query.size() > 2 && query.get(1) instanceof String[] && ((String[])query.get(1)).length ==1) ref += " "+((String[])query.get(1))[0]; StringBuilder out = new StringBuilder(); if (arg instanceof Thing) { if (!empty(ref)) out.append(ref).append(' '); out.append(toString((Thing)arg)); } else { if (!empty(ref)) out.append(ref).append(' '); Collection things = (Collection)arg; if (AL.empty(things)){ out.append(no[0]); }else { String[] sorted = new String[things.size()]; int c = 0; for (Iterator it = things.iterator(); it.hasNext(); ) sorted[c++] = toString(it.next()); Arrays.sort(sorted); for (int i=0;i<sorted.length;i++) { if (i > 0) out.append(';').append(space); out.append(sorted[i]); } } } out.append('.'); return capitalize(out); } public static String capitalize(StringBuilder builder) { if (builder.length() > 0) builder.setCharAt(0,Character.toUpperCase(builder.charAt(0))); return builder.toString(); } public static String capitalize(String string) { return string == null? null : capitalize(new StringBuilder(string)).toString(); } //JSONify public static String toJSON(Object arg, Thing context){ if (arg == null) return ""; if (arg instanceof Object[] || arg instanceof Object){ StringBuilder sb = new StringBuilder(); toJSON(sb,arg,context); return sb.toString(); } return arg.toString(); } //https://codebeautify.org/jsonvalidator public static void toJSON(StringBuilder sb, Object arg, Thing context){ if (arg instanceof Object[]){ Object[] objs = (Object[]) arg; sb.append('['); for (int i = 0; i < objs.length; i++){ if (i > 0) sb.append(','); toJSON(sb,objs[i],context); } sb.append(']'); } else if (arg instanceof Set){ Set set = (Set) arg; //TODO: negation? int size = set.size(); //TODO: type? sb.append('['); for (int i=0; i<size; i++) { if (i > 0) { sb.append(','); } toJSON(sb,set.get(i),context); } sb.append(']'); } else if (arg instanceof Collection){ Collection coll = (Collection)arg; String[] sorted = new String[coll.size()]; int c = 0; for (Iterator it = coll.iterator(); it.hasNext(); ) sorted[c++] = toJSON(it.next(),context); Arrays.sort(sorted); sb.append('['); for (int i=0; i<sorted.length; i++) { if (i > 0) { sb.append(','); } sb.append(sorted[i]); } sb.append(']'); } else if (arg instanceof Map){ Map map = (Map) arg; int count = 0; sb.append('{'); TreeSet keys = new TreeSet(map.keySet()); //map.keySet() for (Iterator i = keys.iterator(); i.hasNext();){ Object k = i.next(); Object v = map.get(k); if (k != null && v != null){ if (count++ > 0) sb.append(','); sb.append('\"').append(k.toString()).append("\":").append(toJSON(v,context)); } } sb.append('}'); } else if (arg instanceof Thing){ toJSON(sb, (Thing) arg, context);//as a JSON } else if (arg instanceof String){ String s = (String)arg; s = s.replace("\"", "\\\""); s = s.replace("\\", "\\\\"); s = s.replace("\t", " "); sb.append('\"').append(s).append('\"'); } else { sb.append('\"'); toString(sb,arg,null); sb.append('\"'); } } public static void toJSON(StringBuilder out,Thing thing, Thing context) { //TODO: make unique reference AKA buildQualifier String ref = thing.getString(name); if (context != null && !AL.empty(ref)) { toJSON(out,ref,context); } else //TODO: do more fancy stuff like toString? { out.append('{'); String[] names = thing.getNamesAvailable(); { String[] sorted = new String[names.length]; for (int i=0, c=0;i<names.length;i++) { String name = (String)names[i]; Object value = thing.get(name); if (value != null) sorted[c++] = '\"' + name + "\":" + toJSON(value,thing); } Arrays.sort(sorted); for (int i=0; i<names.length; i++) { if (i > 0) out.append(','); out.append(sorted[i]); } } out.append('}'); } } //TODO: turn into separate class for HTML/JSON/XLSX public static String toHTML(Object arg,java.util.Set properties){ if (arg == null) return ""; if (arg instanceof Object[] || arg instanceof Object){ StringBuilder sb = new StringBuilder(); toHTML(sb,arg,properties,false); return sb.toString(); } return arg.toString(); } private static java.util.Set getProps(Object arg){ if (arg instanceof Map) return ((Map)arg).keySet(); if (arg instanceof Thing) return Str.hset(((Thing)arg).getNamesAvailable()); return new HashSet(); } static final String table_start = "<table border=\"1\" style=\"border-collapse:collapse;\">\n"; static final String header_start = "<tr><th>"; static final String header_break = "</th><th>"; static final String header_stop = "</th></tr>\n"; static final String rows_start = "<tr><td style=\"vertical-align:top;\">"; static final String cell_break = "</td><td style=\"vertical-align:top;\">"; static final String row_break = "</td></tr>\n<tr><td>"; static final String table_stop = "</td></tr>\n</table>"; public static void toHTML(StringBuilder sb, Object arg, String property){ if (arg instanceof java.util.Set){//pass properties as hack to indicate encloseness java.util.Set set = (java.util.Set) arg;//properties of a Thing! //TODO: negation? int i = 0; for (Object o : set) { if (i++ > 0) sb.append(";<br>"); if (o instanceof Thing) { String n = ((Thing) o).name(); if (!AL.empty(n)) o = n; } toHTML(sb, o, property); } } else if (arg instanceof String){ String s = (String)arg; String breakingstyle="overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;"; sb.append(AL.isIMG(s) || "image".equals(property) ? "<img style=\"height:64px;width:auto;\" src=\""+s+"\"/>" : AL.isURL(s) ? "<a style=\""+breakingstyle+"\" href=\""+s+"\" target=\"_blank\">"+s+"</a>" : HtmlStripper.encodeHTML(s)); } else { sb.append(HtmlStripper.encodeHTML(arg.toString())); } } public static void toHTML(StringBuilder sb, Object arg, java.util.Set properties, boolean sort){ if (arg instanceof Object[]){ TreeSet props = new TreeSet(); Object[] objs = (Object[]) arg; sb.append(table_start); for (int i = 0; i < objs.length; i++) props.addAll(getProps(objs)); if (!AL.empty(props)) { sb.append(header_start); int i = 0; for (Object p : props) { if (i++ > 0) sb.append(header_break); sb.append(capitalize((String)p)); } sb.append(header_stop); } sb.append(rows_start); for (int i = 0; i < objs.length; i++){ if (i > 0) sb.append(row_break); toHTML(sb,objs[i],props,sort); } sb.append(table_stop); } else if (arg instanceof Collection && properties == null){//pass properties as hack to indicate encloseness TreeSet props = new TreeSet(); Collection coll = (Collection)arg; String[] sorted = new String[coll.size()]; for (Object o : coll) props.addAll(getProps(o)); sb.append(table_start); if (!AL.empty(props)) { sb.append(header_start); int i = 0; for (Object p : props) { if (i++ > 0) sb.append(header_break); sb.append(capitalize((String)p)); } sb.append(header_stop); } int c = 0; for (Iterator it = coll.iterator(); it.hasNext(); ) sorted[c++] = toHTML(it.next(),props); if (sort) Arrays.sort(sorted); sb.append(rows_start); for (int i=0; i<sorted.length; i++) { if (i > 0) { sb.append(row_break); } sb.append(sorted[i]); } sb.append(table_stop); } else if (arg instanceof Map){ Map map = (Map) arg; int count = 0; TreeSet keys = new TreeSet(!AL.empty(properties) ? properties : map.keySet()); //sorted!? for (Iterator i = keys.iterator(); i.hasNext();){ Object k = i.next(); Object v = map.get(k); if (k != null && v != null){ if (count++ > 0) sb.append(cell_break); toHTML(sb,v,(String)k); } } } else if (arg instanceof Thing){ int count = 0; TreeSet keys = new TreeSet(!AL.empty(properties) ? properties : getProps(arg)); //sorted!? for (Iterator i = keys.iterator(); i.hasNext();){ Object k = i.next(); Object v = ((Thing)arg).get((String)k); if (count++ > 0) sb.append(cell_break); if (k != null && v != null) toHTML(sb,v,(String)k);//pass properties as hack to indicate encloseness else sb.append(" "); } } } }