001 package org.apache.tapestry.json; 002 003 /* 004 Copyright (c) 2002 JSON.org 005 006 Permission is hereby granted, free of charge, to any person obtaining a copy 007 of this software and associated documentation files (the "Software"), to deal 008 in the Software without restriction, including without limitation the rights 009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 copies of the Software, and to permit persons to whom the Software is 011 furnished to do so, subject to the following conditions: 012 013 The above copyright notice and this permission notice shall be included in all 014 copies or substantial portions of the Software. 015 016 The Software shall be used for Good, not Evil. 017 018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 019 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 020 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 021 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 022 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 023 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 024 SOFTWARE. 025 */ 026 027 import java.text.ParseException; 028 029 /** 030 * This provides static methods to convert comma delimited text into a 031 * JSONArray, and to covert a JSONArray into comma delimited text. Comma 032 * delimited text is a very popular format for data interchange. It is 033 * understood by most database, spreadsheet, and organizer programs. 034 * <p> 035 * Each row of text represents a row in a table or a data record. Each row ends 036 * with a NEWLINE character. Each row contains one or more values. Values are 037 * separated by commas. A value can contain any character except for comma, 038 * unless is is wrapped in single quotes or double quotes. 039 * <p> 040 * The first row usually contains the names of the columns. 041 * <p> 042 * A comma delimited list can be converted into a JSONArray of JSONObjects. The 043 * names for the elements in the JSONObjects can be taken from the names in the 044 * first row. 045 */ 046 public final class CDL 047 { 048 049 /* defeat instantiation */ 050 private CDL() 051 { 052 } 053 054 /** 055 * Get the next value. The value can be wrapped in quotes. The value can be 056 * empty. 057 * 058 * @param x 059 * A JSONTokener of the source text. 060 * @return The value string, or null if empty. 061 * @throws java.text.ParseException 062 * if the quoted string is badly formed. 063 */ 064 private static String getValue(JSONTokener x) 065 throws java.text.ParseException 066 { 067 char c; 068 do 069 { 070 c = x.next(); 071 } while(c <= ' ' && c != 0); 072 switch(c) 073 { 074 case 0: 075 return null; 076 case '"': 077 case '\'': 078 return x.nextString(c); 079 case ',': 080 x.back(); 081 return ""; 082 default: 083 x.back(); 084 return x.nextTo(','); 085 } 086 } 087 088 /** 089 * Produce a JSONArray of strings from a row of comma delimited values. 090 * 091 * @param x 092 * A JSONTokener of the source text. 093 * @return A JSONArray of strings. 094 * @throws ParseException 095 */ 096 public static JSONArray rowToJSONArray(JSONTokener x) 097 throws ParseException 098 { 099 JSONArray ja = new JSONArray(); 100 while(true) 101 { 102 String value = getValue(x); 103 if (value == null) { return null; } 104 ja.put(value); 105 while(true) 106 { 107 char c = x.next(); 108 if (c == ',') 109 { 110 break; 111 } 112 if (c != ' ') 113 { 114 if (c == '\n' || c == '\r' || c == 0) { return ja; } 115 throw x.syntaxError("Bad character '" + c + "' (" + (int) c 116 + ")."); 117 } 118 } 119 } 120 } 121 122 /** 123 * Produce a JSONObject from a row of comma delimited text, using a parallel 124 * JSONArray of strings to provides the names of the elements. 125 * 126 * @param names 127 * A JSONArray of names. This is commonly obtained from the first 128 * row of a comma delimited text file using the rowToJSONArray 129 * method. 130 * @param x 131 * A JSONTokener of the source text. 132 * @return A JSONObject combining the names and values. 133 * @throws ParseException 134 */ 135 public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) 136 throws ParseException 137 { 138 JSONArray ja = rowToJSONArray(x); 139 return ja != null ? ja.toJSONObject(names) : null; 140 } 141 142 /** 143 * Produce a JSONArray of JSONObjects from a comma delimited text string, 144 * using the first row as a source of names. 145 * 146 * @param string 147 * The comma delimited text. 148 * @return A JSONArray of JSONObjects. 149 * @throws ParseException 150 */ 151 public static JSONArray toJSONArray(String string) 152 throws ParseException 153 { 154 return toJSONArray(new JSONTokener(string)); 155 } 156 157 /** 158 * Produce a JSONArray of JSONObjects from a comma delimited text string, 159 * using the first row as a source of names. 160 * 161 * @param x 162 * The JSONTokener containing the comma delimited text. 163 * @return A JSONArray of JSONObjects. 164 * @throws ParseException 165 */ 166 public static JSONArray toJSONArray(JSONTokener x) 167 throws ParseException 168 { 169 return toJSONArray(rowToJSONArray(x), x); 170 } 171 172 /** 173 * Produce a JSONArray of JSONObjects from a comma delimited text string 174 * using a supplied JSONArray as the source of element names. 175 * 176 * @param names 177 * A JSONArray of strings. 178 * @param string 179 * The comma delimited text. 180 * @return A JSONArray of JSONObjects. 181 * @throws ParseException 182 */ 183 public static JSONArray toJSONArray(JSONArray names, String string) 184 throws ParseException 185 { 186 return toJSONArray(names, new JSONTokener(string)); 187 } 188 189 /** 190 * Produce a JSONArray of JSONObjects from a comma delimited text string 191 * using a supplied JSONArray as the source of element names. 192 * 193 * @param names 194 * A JSONArray of strings. 195 * @param x 196 * A JSONTokener of the source text. 197 * @return A JSONArray of JSONObjects. 198 * @throws java.text.ParseException 199 */ 200 public static JSONArray toJSONArray(JSONArray names, JSONTokener x) 201 throws java.text.ParseException 202 { 203 if (names == null || names.length() == 0) { return null; } 204 JSONArray ja = new JSONArray(); 205 while(true) 206 { 207 JSONObject jo = rowToJSONObject(names, x); 208 if (jo == null) 209 { 210 break; 211 } 212 ja.put(jo); 213 } 214 if (ja.length() == 0) { return null; } 215 return ja; 216 } 217 218 /** 219 * Produce a comma delimited text row from a JSONArray. Values containing 220 * the comma character will be quoted. 221 * 222 * @param ja 223 * A JSONArray of strings. 224 * @return A string ending in NEWLINE. 225 */ 226 public static String rowToString(JSONArray ja) 227 { 228 StringBuffer sb = new StringBuffer(); 229 for(int i = 0; i < ja.length(); i += 1) 230 { 231 if (i > 0) 232 { 233 sb.append(','); 234 } 235 Object o = ja.opt(i); 236 if (o != null) 237 { 238 String s = o.toString(); 239 if (s.indexOf(',') >= 0) 240 { 241 if (s.indexOf('"') >= 0) 242 { 243 sb.append('\''); 244 sb.append(s); 245 sb.append('\''); 246 } 247 else 248 { 249 sb.append('"'); 250 sb.append(s); 251 sb.append('"'); 252 } 253 } 254 else 255 { 256 sb.append(s); 257 } 258 } 259 } 260 sb.append('\n'); 261 return sb.toString(); 262 263 } 264 265 /** 266 * Produce a comma delimited text from a JSONArray of JSONObjects. The first 267 * row will be a list of names obtained by inspecting the first JSONObject. 268 * 269 * @param ja 270 * A JSONArray of JSONObjects. 271 * @return A comma delimited text. 272 */ 273 public static String toString(JSONArray ja) 274 { 275 JSONObject jo = ja.optJSONObject(0); 276 if (jo != null) 277 { 278 JSONArray names = jo.names(); 279 if (names != null) { return rowToString(names) 280 + toString(names, ja); } 281 } 282 return null; 283 } 284 285 /** 286 * Produce a comma delimited text from a JSONArray of JSONObjects using a 287 * provided list of names. The list of names is not included in the output. 288 * 289 * @param names 290 * A JSONArray of strings. 291 * @param ja 292 * A JSONArray of JSONObjects. 293 * @return A comma delimited text. 294 */ 295 public static String toString(JSONArray names, JSONArray ja) 296 { 297 if (names == null || names.length() == 0) { return null; } 298 StringBuffer sb = new StringBuffer(); 299 for(int i = 0; i < ja.length(); i += 1) 300 { 301 JSONObject jo = ja.optJSONObject(i); 302 if (jo != null) 303 { 304 sb.append(rowToString(jo.toJSONArray(names))); 305 } 306 } 307 return sb.toString(); 308 } 309 }