001package gudusoft.gsqlparser.util.json; 002 003public class JSONUtil { 004 005 /** 006 * Efficiently extracts a top-level string field value from a JSON object 007 * without full parsing. Only scans the top-level keys of the JSON structure, 008 * skipping nested objects and arrays by tracking brace/bracket depth. 009 * Returns {@code null} if the field is not found or its value is not a string. 010 * <p> 011 * This avoids the cost of building a full object tree via 012 * {@code JSON.parseObject()} when only a few top-level fields are needed. 013 */ 014 public static String extractTopLevelStringField(String json, String fieldName) { 015 if (json == null || json.isEmpty()) { 016 return null; 017 } 018 String trimmed = json.trim(); 019 int idx = 0; 020 int len = trimmed.length(); 021 int braceDepth = 0; 022 int bracketDepth = 0; 023 024 while (idx < len && trimmed.charAt(idx) != '{') { 025 idx++; 026 } 027 if (idx >= len) { 028 return null; 029 } 030 idx++; 031 braceDepth = 1; 032 033 while (idx < len && braceDepth > 0) { 034 char c = trimmed.charAt(idx); 035 036 if (c == '"') { 037 int stringStart = idx; 038 idx++; 039 while (idx < len) { 040 c = trimmed.charAt(idx); 041 if (c == '\\') { 042 idx += 2; 043 } else if (c == '"') { 044 idx++; 045 break; 046 } else { 047 idx++; 048 } 049 } 050 051 if (braceDepth == 1 && bracketDepth == 0) { 052 String key = trimmed.substring(stringStart + 1, idx - 1); 053 if (key.equals(fieldName)) { 054 while (idx < len && (trimmed.charAt(idx) == ':' || Character.isWhitespace(trimmed.charAt(idx)))) { 055 idx++; 056 } 057 if (idx < len && trimmed.charAt(idx) == '"') { 058 int valStart = idx + 1; 059 idx++; 060 while (idx < len) { 061 c = trimmed.charAt(idx); 062 if (c == '\\') { 063 idx += 2; 064 } else if (c == '"') { 065 return trimmed.substring(valStart, idx); 066 } else { 067 idx++; 068 } 069 } 070 } 071 return null; 072 } 073 } 074 } else if (c == '{') { 075 braceDepth++; 076 idx++; 077 } else if (c == '}') { 078 braceDepth--; 079 idx++; 080 } else if (c == '[') { 081 bracketDepth++; 082 idx++; 083 } else if (c == ']') { 084 bracketDepth--; 085 idx++; 086 } else { 087 idx++; 088 } 089 } 090 return null; 091 } 092 093 /** 094 * Efficiently extracts the raw text value of a top-level field from a JSON object 095 * without full parsing. Works for any JSON value type: string, number, boolean, 096 * and null. Only scans the top-level keys of the JSON structure, skipping nested 097 * objects and arrays by tracking brace/bracket depth. 098 * Returns {@code null} if the field is not found. 099 * <p> 100 * For string values, the surrounding quotes are stripped. For all other value 101 * types (number, boolean, null), the raw text is returned as-is. 102 */ 103 public static String extractTopLevelFieldValue(String json, String fieldName) { 104 if (json == null || json.isEmpty()) { 105 return null; 106 } 107 String trimmed = json.trim(); 108 int idx = 0; 109 int len = trimmed.length(); 110 int braceDepth = 0; 111 int bracketDepth = 0; 112 113 while (idx < len && trimmed.charAt(idx) != '{') { 114 idx++; 115 } 116 if (idx >= len) { 117 return null; 118 } 119 idx++; 120 braceDepth = 1; 121 122 while (idx < len && braceDepth > 0) { 123 char c = trimmed.charAt(idx); 124 125 if (c == '"') { 126 int stringStart = idx; 127 idx++; 128 while (idx < len) { 129 c = trimmed.charAt(idx); 130 if (c == '\\') { 131 idx += 2; 132 } else if (c == '"') { 133 idx++; 134 break; 135 } else { 136 idx++; 137 } 138 } 139 140 if (braceDepth == 1 && bracketDepth == 0) { 141 String key = trimmed.substring(stringStart + 1, idx - 1); 142 if (key.equals(fieldName)) { 143 while (idx < len && (trimmed.charAt(idx) == ':' || Character.isWhitespace(trimmed.charAt(idx)))) { 144 idx++; 145 } 146 if (idx >= len) { 147 return null; 148 } 149 if (trimmed.charAt(idx) == '"') { 150 int valStart = idx + 1; 151 idx++; 152 while (idx < len) { 153 c = trimmed.charAt(idx); 154 if (c == '\\') { 155 idx += 2; 156 } else if (c == '"') { 157 return trimmed.substring(valStart, idx); 158 } else { 159 idx++; 160 } 161 } 162 return null; 163 } 164 int valStart = idx; 165 while (idx < len) { 166 c = trimmed.charAt(idx); 167 if (c == ',' || c == '}' || c == ']' || Character.isWhitespace(c)) { 168 break; 169 } 170 idx++; 171 } 172 String raw = trimmed.substring(valStart, idx); 173 return raw.isEmpty() ? null : raw; 174 } 175 } 176 } else if (c == '{') { 177 braceDepth++; 178 idx++; 179 } else if (c == '}') { 180 braceDepth--; 181 idx++; 182 } else if (c == '[') { 183 bracketDepth++; 184 idx++; 185 } else if (c == ']') { 186 bracketDepth--; 187 idx++; 188 } else { 189 idx++; 190 } 191 } 192 return null; 193 } 194}