Commit cdf43d88f6894f52f9908aa3a39d35d38905ab82
1 parent
a37b2416
调度语音识别
Showing
45 changed files
with
9199 additions
and
80 deletions
pom.xml
| ... | ... | @@ -411,6 +411,24 @@ |
| 411 | 411 | <groupId>org.hibernate</groupId> |
| 412 | 412 | <artifactId>hibernate-spatial</artifactId> |
| 413 | 413 | </dependency> |
| 414 | + | |
| 415 | + <!-- 语音识别 --> | |
| 416 | + <dependency> | |
| 417 | + <groupId>net.java.dev.jna</groupId> | |
| 418 | + <artifactId>jna</artifactId> | |
| 419 | + <version>5.7.0</version> | |
| 420 | + </dependency> | |
| 421 | + <dependency> | |
| 422 | + <groupId>com.alphacephei</groupId> | |
| 423 | + <artifactId>vosk</artifactId> | |
| 424 | + <version>0.3.32</version> | |
| 425 | + </dependency> | |
| 426 | + | |
| 427 | + <dependency> | |
| 428 | + <groupId>com.belerweb</groupId> | |
| 429 | + <artifactId>pinyin4j</artifactId> | |
| 430 | + <version>2.5.1</version> | |
| 431 | + </dependency> | |
| 414 | 432 | </dependencies> |
| 415 | 433 | |
| 416 | 434 | <dependencyManagement> | ... | ... |
src/main/java/com/bsth/controller/realcontrol/PageForwardingController.java
| 1 | 1 | package com.bsth.controller.realcontrol; |
| 2 | 2 | |
| 3 | +import com.bsth.data.zndd.voice.UploadVideoServlet; | |
| 3 | 4 | import com.bsth.entity.sys.Role; |
| 4 | 5 | import com.bsth.entity.sys.SysUser; |
| 5 | 6 | import com.bsth.security.util.SecurityUtils; |
| 6 | 7 | import org.slf4j.Logger; |
| 7 | 8 | import org.slf4j.LoggerFactory; |
| 9 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 8 | 10 | import org.springframework.stereotype.Controller; |
| 11 | +import org.springframework.web.bind.annotation.PathVariable; | |
| 9 | 12 | import org.springframework.web.bind.annotation.RequestMapping; |
| 13 | +import org.springframework.web.bind.annotation.RequestParam; | |
| 10 | 14 | import org.springframework.web.servlet.ModelAndView; |
| 11 | 15 | |
| 16 | +import javax.servlet.ServletException; | |
| 17 | +import javax.servlet.http.HttpServletRequest; | |
| 12 | 18 | import javax.servlet.http.HttpServletResponse; |
| 19 | +import java.io.IOException; | |
| 13 | 20 | |
| 14 | 21 | /** |
| 15 | 22 | * 线调登入页面转发 |
| ... | ... | @@ -21,6 +28,8 @@ public class PageForwardingController { |
| 21 | 28 | |
| 22 | 29 | Logger logger = LoggerFactory.getLogger(this.getClass()); |
| 23 | 30 | |
| 31 | + @Autowired | |
| 32 | + UploadVideoServlet UploadVideoServlet; | |
| 24 | 33 | @RequestMapping("/v2") |
| 25 | 34 | public ModelAndView v2(HttpServletResponse response){ |
| 26 | 35 | ModelAndView mv = new ModelAndView(); |
| ... | ... | @@ -51,4 +60,9 @@ public class PageForwardingController { |
| 51 | 60 | mv.setViewName("/real_control_v2/main.html"); |
| 52 | 61 | return mv; |
| 53 | 62 | } |
| 63 | + | |
| 64 | + @RequestMapping(value = "zndd/do/{line}") | |
| 65 | + public void doPost(@PathVariable("line") String line, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
| 66 | + UploadVideoServlet.doPost(line,request,response); | |
| 67 | + } | |
| 54 | 68 | } | ... | ... |
src/main/java/com/bsth/controller/zndd/LoggerZnddController.java
| 1 | 1 | package com.bsth.controller.zndd; |
| 2 | 2 | |
| 3 | 3 | import com.bsth.controller.BaseController; |
| 4 | +import com.bsth.entity.realcontrol.ScheduleRealInfo; | |
| 4 | 5 | import com.bsth.entity.zndd.LoggerZndd; |
| 5 | 6 | import com.bsth.service.zndd.LoggerZnddService; |
| 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; |
| 7 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 8 | -import org.springframework.web.bind.annotation.RequestParam; | |
| 9 | -import org.springframework.web.bind.annotation.RestController; | |
| 10 | - | |
| 8 | +import org.springframework.web.bind.annotation.*; | |
| 11 | 9 | import java.util.List; |
| 12 | 10 | import java.util.Map; |
| 13 | 11 | |
| ... | ... | @@ -17,9 +15,17 @@ public class LoggerZnddController extends BaseController<LoggerZndd, Integer> { |
| 17 | 15 | |
| 18 | 16 | @Autowired |
| 19 | 17 | LoggerZnddService loggerZnddService; |
| 18 | + | |
| 20 | 19 | @RequestMapping("listall") |
| 21 | 20 | public List<Map<String, Object>> listAll(@RequestParam Map<String, Object> map){ |
| 22 | 21 | |
| 23 | 22 | return loggerZnddService.listAll(map); |
| 24 | 23 | } |
| 24 | + | |
| 25 | + | |
| 26 | + @RequestMapping(value = "/schlist", method = RequestMethod.POST) | |
| 27 | + public ScheduleRealInfo schlist(@RequestParam String lineCode,@RequestParam Integer dir){ | |
| 28 | + return loggerZnddService.schlist(lineCode,dir); | |
| 29 | + } | |
| 30 | + | |
| 25 | 31 | } | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/CDL.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | + */ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * This provides static methods to convert comma delimited text into a | |
| 29 | + * JSONArray, and to convert a JSONArray into comma delimited text. Comma | |
| 30 | + * delimited text is a very popular format for data interchange. It is | |
| 31 | + * understood by most database, spreadsheet, and organizer programs. | |
| 32 | + * <p> | |
| 33 | + * Each row of text represents a row in a table or a data record. Each row | |
| 34 | + * ends with a NEWLINE character. Each row contains one or more values. | |
| 35 | + * Values are separated by commas. A value can contain any character except | |
| 36 | + * for comma, unless is is wrapped in single quotes or double quotes. | |
| 37 | + * <p> | |
| 38 | + * The first row usually contains the names of the columns. | |
| 39 | + * <p> | |
| 40 | + * A comma delimited list can be converted into a JSONArray of JSONObjects. | |
| 41 | + * The names for the elements in the JSONObjects can be taken from the names | |
| 42 | + * in the first row. | |
| 43 | + * @author JSON.org | |
| 44 | + * @version 2016-05-01 | |
| 45 | + */ | |
| 46 | +public class CDL { | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Get the next value. The value can be wrapped in quotes. The value can | |
| 50 | + * be empty. | |
| 51 | + * @param x A JSONTokener of the source text. | |
| 52 | + * @return The value string, or null if empty. | |
| 53 | + * @throws JSONException if the quoted string is badly formed. | |
| 54 | + */ | |
| 55 | + private static String getValue(JSONTokener x) throws JSONException { | |
| 56 | + char c; | |
| 57 | + char q; | |
| 58 | + StringBuffer sb; | |
| 59 | + do { | |
| 60 | + c = x.next(); | |
| 61 | + } while (c == ' ' || c == '\t'); | |
| 62 | + switch (c) { | |
| 63 | + case 0: | |
| 64 | + return null; | |
| 65 | + case '"': | |
| 66 | + case '\'': | |
| 67 | + q = c; | |
| 68 | + sb = new StringBuffer(); | |
| 69 | + for (;;) { | |
| 70 | + c = x.next(); | |
| 71 | + if (c == q) { | |
| 72 | + //Handle escaped double-quote | |
| 73 | + char nextC = x.next(); | |
| 74 | + if(nextC != '\"') { | |
| 75 | + // if our quote was the end of the file, don't step | |
| 76 | + if(nextC > 0) { | |
| 77 | + x.back(); | |
| 78 | + } | |
| 79 | + break; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + if (c == 0 || c == '\n' || c == '\r') { | |
| 83 | + throw x.syntaxError("Missing close quote '" + q + "'."); | |
| 84 | + } | |
| 85 | + sb.append(c); | |
| 86 | + } | |
| 87 | + return sb.toString(); | |
| 88 | + case ',': | |
| 89 | + x.back(); | |
| 90 | + return ""; | |
| 91 | + default: | |
| 92 | + x.back(); | |
| 93 | + return x.nextTo(','); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Produce a JSONArray of strings from a row of comma delimited values. | |
| 99 | + * @param x A JSONTokener of the source text. | |
| 100 | + * @return A JSONArray of strings. | |
| 101 | + * @throws JSONException | |
| 102 | + */ | |
| 103 | + public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { | |
| 104 | + JSONArray ja = new JSONArray(); | |
| 105 | + for (;;) { | |
| 106 | + String value = getValue(x); | |
| 107 | + char c = x.next(); | |
| 108 | + if (value == null || | |
| 109 | + (ja.length() == 0 && value.length() == 0 && c != ',')) { | |
| 110 | + return null; | |
| 111 | + } | |
| 112 | + ja.put(value); | |
| 113 | + for (;;) { | |
| 114 | + if (c == ',') { | |
| 115 | + break; | |
| 116 | + } | |
| 117 | + if (c != ' ') { | |
| 118 | + if (c == '\n' || c == '\r' || c == 0) { | |
| 119 | + return ja; | |
| 120 | + } | |
| 121 | + throw x.syntaxError("Bad character '" + c + "' (" + | |
| 122 | + (int)c + ")."); | |
| 123 | + } | |
| 124 | + c = x.next(); | |
| 125 | + } | |
| 126 | + } | |
| 127 | + } | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * Produce a JSONObject from a row of comma delimited text, using a | |
| 131 | + * parallel JSONArray of strings to provides the names of the elements. | |
| 132 | + * @param names A JSONArray of names. This is commonly obtained from the | |
| 133 | + * first row of a comma delimited text file using the rowToJSONArray | |
| 134 | + * method. | |
| 135 | + * @param x A JSONTokener of the source text. | |
| 136 | + * @return A JSONObject combining the names and values. | |
| 137 | + * @throws JSONException | |
| 138 | + */ | |
| 139 | + public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) | |
| 140 | + throws JSONException { | |
| 141 | + JSONArray ja = rowToJSONArray(x); | |
| 142 | + return ja != null ? ja.toJSONObject(names) : null; | |
| 143 | + } | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * Produce a comma delimited text row from a JSONArray. Values containing | |
| 147 | + * the comma character will be quoted. Troublesome characters may be | |
| 148 | + * removed. | |
| 149 | + * @param ja A JSONArray of strings. | |
| 150 | + * @return A string ending in NEWLINE. | |
| 151 | + */ | |
| 152 | + public static String rowToString(JSONArray ja) { | |
| 153 | + StringBuilder sb = new StringBuilder(); | |
| 154 | + for (int i = 0; i < ja.length(); i += 1) { | |
| 155 | + if (i > 0) { | |
| 156 | + sb.append(','); | |
| 157 | + } | |
| 158 | + Object object = ja.opt(i); | |
| 159 | + if (object != null) { | |
| 160 | + String string = object.toString(); | |
| 161 | + if (string.length() > 0 && (string.indexOf(',') >= 0 || | |
| 162 | + string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || | |
| 163 | + string.indexOf(0) >= 0 || string.charAt(0) == '"')) { | |
| 164 | + sb.append('"'); | |
| 165 | + int length = string.length(); | |
| 166 | + for (int j = 0; j < length; j += 1) { | |
| 167 | + char c = string.charAt(j); | |
| 168 | + if (c >= ' ' && c != '"') { | |
| 169 | + sb.append(c); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + sb.append('"'); | |
| 173 | + } else { | |
| 174 | + sb.append(string); | |
| 175 | + } | |
| 176 | + } | |
| 177 | + } | |
| 178 | + sb.append('\n'); | |
| 179 | + return sb.toString(); | |
| 180 | + } | |
| 181 | + | |
| 182 | + /** | |
| 183 | + * Produce a JSONArray of JSONObjects from a comma delimited text string, | |
| 184 | + * using the first row as a source of names. | |
| 185 | + * @param string The comma delimited text. | |
| 186 | + * @return A JSONArray of JSONObjects. | |
| 187 | + * @throws JSONException | |
| 188 | + */ | |
| 189 | + public static JSONArray toJSONArray(String string) throws JSONException { | |
| 190 | + return toJSONArray(new JSONTokener(string)); | |
| 191 | + } | |
| 192 | + | |
| 193 | + /** | |
| 194 | + * Produce a JSONArray of JSONObjects from a comma delimited text string, | |
| 195 | + * using the first row as a source of names. | |
| 196 | + * @param x The JSONTokener containing the comma delimited text. | |
| 197 | + * @return A JSONArray of JSONObjects. | |
| 198 | + * @throws JSONException | |
| 199 | + */ | |
| 200 | + public static JSONArray toJSONArray(JSONTokener x) throws JSONException { | |
| 201 | + return toJSONArray(rowToJSONArray(x), x); | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * Produce a JSONArray of JSONObjects from a comma delimited text string | |
| 206 | + * using a supplied JSONArray as the source of element names. | |
| 207 | + * @param names A JSONArray of strings. | |
| 208 | + * @param string The comma delimited text. | |
| 209 | + * @return A JSONArray of JSONObjects. | |
| 210 | + * @throws JSONException | |
| 211 | + */ | |
| 212 | + public static JSONArray toJSONArray(JSONArray names, String string) | |
| 213 | + throws JSONException { | |
| 214 | + return toJSONArray(names, new JSONTokener(string)); | |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * Produce a JSONArray of JSONObjects from a comma delimited text string | |
| 219 | + * using a supplied JSONArray as the source of element names. | |
| 220 | + * @param names A JSONArray of strings. | |
| 221 | + * @param x A JSONTokener of the source text. | |
| 222 | + * @return A JSONArray of JSONObjects. | |
| 223 | + * @throws JSONException | |
| 224 | + */ | |
| 225 | + public static JSONArray toJSONArray(JSONArray names, JSONTokener x) | |
| 226 | + throws JSONException { | |
| 227 | + if (names == null || names.length() == 0) { | |
| 228 | + return null; | |
| 229 | + } | |
| 230 | + JSONArray ja = new JSONArray(); | |
| 231 | + for (;;) { | |
| 232 | + JSONObject jo = rowToJSONObject(names, x); | |
| 233 | + if (jo == null) { | |
| 234 | + break; | |
| 235 | + } | |
| 236 | + ja.put(jo); | |
| 237 | + } | |
| 238 | + if (ja.length() == 0) { | |
| 239 | + return null; | |
| 240 | + } | |
| 241 | + return ja; | |
| 242 | + } | |
| 243 | + | |
| 244 | + | |
| 245 | + /** | |
| 246 | + * Produce a comma delimited text from a JSONArray of JSONObjects. The | |
| 247 | + * first row will be a list of names obtained by inspecting the first | |
| 248 | + * JSONObject. | |
| 249 | + * @param ja A JSONArray of JSONObjects. | |
| 250 | + * @return A comma delimited text. | |
| 251 | + * @throws JSONException | |
| 252 | + */ | |
| 253 | + public static String toString(JSONArray ja) throws JSONException { | |
| 254 | + JSONObject jo = ja.optJSONObject(0); | |
| 255 | + if (jo != null) { | |
| 256 | + JSONArray names = jo.names(); | |
| 257 | + if (names != null) { | |
| 258 | + return rowToString(names) + toString(names, ja); | |
| 259 | + } | |
| 260 | + } | |
| 261 | + return null; | |
| 262 | + } | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Produce a comma delimited text from a JSONArray of JSONObjects using | |
| 266 | + * a provided list of names. The list of names is not included in the | |
| 267 | + * output. | |
| 268 | + * @param names A JSONArray of strings. | |
| 269 | + * @param ja A JSONArray of JSONObjects. | |
| 270 | + * @return A comma delimited text. | |
| 271 | + * @throws JSONException | |
| 272 | + */ | |
| 273 | + public static String toString(JSONArray names, JSONArray ja) | |
| 274 | + throws JSONException { | |
| 275 | + if (names == null || names.length() == 0) { | |
| 276 | + return null; | |
| 277 | + } | |
| 278 | + StringBuffer sb = new StringBuffer(); | |
| 279 | + for (int i = 0; i < ja.length(); i += 1) { | |
| 280 | + JSONObject jo = ja.optJSONObject(i); | |
| 281 | + if (jo != null) { | |
| 282 | + sb.append(rowToString(jo.toJSONArray(names))); | |
| 283 | + } | |
| 284 | + } | |
| 285 | + return sb.toString(); | |
| 286 | + } | |
| 287 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/Cookie.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * Convert a web browser cookie specification to a JSONObject and back. | |
| 29 | + * JSON and Cookies are both notations for name/value pairs. | |
| 30 | + * @author JSON.org | |
| 31 | + * @version 2015-12-09 | |
| 32 | + */ | |
| 33 | +public class Cookie { | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * Produce a copy of a string in which the characters '+', '%', '=', ';' | |
| 37 | + * and control characters are replaced with "%hh". This is a gentle form | |
| 38 | + * of URL encoding, attempting to cause as little distortion to the | |
| 39 | + * string as possible. The characters '=' and ';' are meta characters in | |
| 40 | + * cookies. By convention, they are escaped using the URL-encoding. This is | |
| 41 | + * only a convention, not a standard. Often, cookies are expected to have | |
| 42 | + * encoded values. We urlEncode '=' and ';' because we must. We urlEncode '%' and | |
| 43 | + * '+' because they are meta characters in URL encoding. | |
| 44 | + * @param string The source string. | |
| 45 | + * @return The escaped result. | |
| 46 | + */ | |
| 47 | + public static String escape(String string) { | |
| 48 | + char c; | |
| 49 | + String s = string.trim(); | |
| 50 | + int length = s.length(); | |
| 51 | + StringBuilder sb = new StringBuilder(length); | |
| 52 | + for (int i = 0; i < length; i += 1) { | |
| 53 | + c = s.charAt(i); | |
| 54 | + if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { | |
| 55 | + sb.append('%'); | |
| 56 | + sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); | |
| 57 | + sb.append(Character.forDigit((char)(c & 0x0f), 16)); | |
| 58 | + } else { | |
| 59 | + sb.append(c); | |
| 60 | + } | |
| 61 | + } | |
| 62 | + return sb.toString(); | |
| 63 | + } | |
| 64 | + | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Convert a cookie specification string into a JSONObject. The string | |
| 68 | + * will contain a name value pair separated by '='. The name and the value | |
| 69 | + * will be unescaped, possibly converting '+' and '%' sequences. The | |
| 70 | + * cookie properties may follow, separated by ';', also represented as | |
| 71 | + * name=value (except the secure property, which does not have a value). | |
| 72 | + * The name will be stored under the key "name", and the value will be | |
| 73 | + * stored under the key "value". This method does not do checking or | |
| 74 | + * validation of the parameters. It only converts the cookie string into | |
| 75 | + * a JSONObject. | |
| 76 | + * @param string The cookie specification string. | |
| 77 | + * @return A JSONObject containing "name", "value", and possibly other | |
| 78 | + * members. | |
| 79 | + * @throws JSONException | |
| 80 | + */ | |
| 81 | + public static JSONObject toJSONObject(String string) throws JSONException { | |
| 82 | + String name; | |
| 83 | + JSONObject jo = new JSONObject(); | |
| 84 | + Object value; | |
| 85 | + JSONTokener x = new JSONTokener(string); | |
| 86 | + jo.put("name", x.nextTo('=')); | |
| 87 | + x.next('='); | |
| 88 | + jo.put("value", x.nextTo(';')); | |
| 89 | + x.next(); | |
| 90 | + while (x.more()) { | |
| 91 | + name = unescape(x.nextTo("=;")); | |
| 92 | + if (x.next() != '=') { | |
| 93 | + if (name.equals("secure")) { | |
| 94 | + value = Boolean.TRUE; | |
| 95 | + } else { | |
| 96 | + throw x.syntaxError("Missing '=' in cookie parameter."); | |
| 97 | + } | |
| 98 | + } else { | |
| 99 | + value = unescape(x.nextTo(';')); | |
| 100 | + x.next(); | |
| 101 | + } | |
| 102 | + jo.put(name, value); | |
| 103 | + } | |
| 104 | + return jo; | |
| 105 | + } | |
| 106 | + | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * Convert a JSONObject into a cookie specification string. The JSONObject | |
| 110 | + * must contain "name" and "value" members. | |
| 111 | + * If the JSONObject contains "expires", "domain", "path", or "secure" | |
| 112 | + * members, they will be appended to the cookie specification string. | |
| 113 | + * All other members are ignored. | |
| 114 | + * @param jo A JSONObject | |
| 115 | + * @return A cookie specification string | |
| 116 | + * @throws JSONException | |
| 117 | + */ | |
| 118 | + public static String toString(JSONObject jo) throws JSONException { | |
| 119 | + StringBuilder sb = new StringBuilder(); | |
| 120 | + | |
| 121 | + sb.append(escape(jo.getString("name"))); | |
| 122 | + sb.append("="); | |
| 123 | + sb.append(escape(jo.getString("value"))); | |
| 124 | + if (jo.has("expires")) { | |
| 125 | + sb.append(";expires="); | |
| 126 | + sb.append(jo.getString("expires")); | |
| 127 | + } | |
| 128 | + if (jo.has("domain")) { | |
| 129 | + sb.append(";domain="); | |
| 130 | + sb.append(escape(jo.getString("domain"))); | |
| 131 | + } | |
| 132 | + if (jo.has("path")) { | |
| 133 | + sb.append(";path="); | |
| 134 | + sb.append(escape(jo.getString("path"))); | |
| 135 | + } | |
| 136 | + if (jo.optBoolean("secure")) { | |
| 137 | + sb.append(";secure"); | |
| 138 | + } | |
| 139 | + return sb.toString(); | |
| 140 | + } | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Convert <code>%</code><i>hh</i> sequences to single characters, and | |
| 144 | + * convert plus to space. | |
| 145 | + * @param string A string that may contain | |
| 146 | + * <code>+</code> <small>(plus)</small> and | |
| 147 | + * <code>%</code><i>hh</i> sequences. | |
| 148 | + * @return The unescaped string. | |
| 149 | + */ | |
| 150 | + public static String unescape(String string) { | |
| 151 | + int length = string.length(); | |
| 152 | + StringBuilder sb = new StringBuilder(length); | |
| 153 | + for (int i = 0; i < length; ++i) { | |
| 154 | + char c = string.charAt(i); | |
| 155 | + if (c == '+') { | |
| 156 | + c = ' '; | |
| 157 | + } else if (c == '%' && i + 2 < length) { | |
| 158 | + int d = JSONTokener.dehexchar(string.charAt(i + 1)); | |
| 159 | + int e = JSONTokener.dehexchar(string.charAt(i + 2)); | |
| 160 | + if (d >= 0 && e >= 0) { | |
| 161 | + c = (char)(d * 16 + e); | |
| 162 | + i += 2; | |
| 163 | + } | |
| 164 | + } | |
| 165 | + sb.append(c); | |
| 166 | + } | |
| 167 | + return sb.toString(); | |
| 168 | + } | |
| 169 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/CookieList.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | + */ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * Convert a web browser cookie list string to a JSONObject and back. | |
| 29 | + * @author JSON.org | |
| 30 | + * @version 2015-12-09 | |
| 31 | + */ | |
| 32 | +public class CookieList { | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * Convert a cookie list into a JSONObject. A cookie list is a sequence | |
| 36 | + * of name/value pairs. The names are separated from the values by '='. | |
| 37 | + * The pairs are separated by ';'. The names and the values | |
| 38 | + * will be unescaped, possibly converting '+' and '%' sequences. | |
| 39 | + * | |
| 40 | + * To add a cookie to a cookie list, | |
| 41 | + * cookielistJSONObject.put(cookieJSONObject.getString("name"), | |
| 42 | + * cookieJSONObject.getString("value")); | |
| 43 | + * @param string A cookie list string | |
| 44 | + * @return A JSONObject | |
| 45 | + * @throws JSONException | |
| 46 | + */ | |
| 47 | + public static JSONObject toJSONObject(String string) throws JSONException { | |
| 48 | + JSONObject jo = new JSONObject(); | |
| 49 | + JSONTokener x = new JSONTokener(string); | |
| 50 | + while (x.more()) { | |
| 51 | + String name = Cookie.unescape(x.nextTo('=')); | |
| 52 | + x.next('='); | |
| 53 | + jo.put(name, Cookie.unescape(x.nextTo(';'))); | |
| 54 | + x.next(); | |
| 55 | + } | |
| 56 | + return jo; | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Convert a JSONObject into a cookie list. A cookie list is a sequence | |
| 61 | + * of name/value pairs. The names are separated from the values by '='. | |
| 62 | + * The pairs are separated by ';'. The characters '%', '+', '=', and ';' | |
| 63 | + * in the names and values are replaced by "%hh". | |
| 64 | + * @param jo A JSONObject | |
| 65 | + * @return A cookie list string | |
| 66 | + * @throws JSONException | |
| 67 | + */ | |
| 68 | + public static String toString(JSONObject jo) throws JSONException { | |
| 69 | + boolean b = false; | |
| 70 | + final StringBuilder sb = new StringBuilder(); | |
| 71 | + // Don't use the new entrySet API to maintain Android support | |
| 72 | + for (final String key : jo.keySet()) { | |
| 73 | + final Object value = jo.opt(key); | |
| 74 | + if (!JSONObject.NULL.equals(value)) { | |
| 75 | + if (b) { | |
| 76 | + sb.append(';'); | |
| 77 | + } | |
| 78 | + sb.append(Cookie.escape(key)); | |
| 79 | + sb.append("="); | |
| 80 | + sb.append(Cookie.escape(value.toString())); | |
| 81 | + b = true; | |
| 82 | + } | |
| 83 | + } | |
| 84 | + return sb.toString(); | |
| 85 | + } | |
| 86 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/HTTP.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +import java.util.Locale; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Convert an HTTP header to a JSONObject and back. | |
| 31 | + * @author JSON.org | |
| 32 | + * @version 2015-12-09 | |
| 33 | + */ | |
| 34 | +public class HTTP { | |
| 35 | + | |
| 36 | + /** Carriage return/line feed. */ | |
| 37 | + public static final String CRLF = "\r\n"; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * Convert an HTTP header string into a JSONObject. It can be a request | |
| 41 | + * header or a response header. A request header will contain | |
| 42 | + * <pre>{ | |
| 43 | + * Method: "POST" (for example), | |
| 44 | + * "Request-URI": "/" (for example), | |
| 45 | + * "HTTP-Version": "HTTP/1.1" (for example) | |
| 46 | + * }</pre> | |
| 47 | + * A response header will contain | |
| 48 | + * <pre>{ | |
| 49 | + * "HTTP-Version": "HTTP/1.1" (for example), | |
| 50 | + * "Status-Code": "200" (for example), | |
| 51 | + * "Reason-Phrase": "OK" (for example) | |
| 52 | + * }</pre> | |
| 53 | + * In addition, the other parameters in the header will be captured, using | |
| 54 | + * the HTTP field names as JSON names, so that <pre> | |
| 55 | + * Date: Sun, 26 May 2002 18:06:04 GMT | |
| 56 | + * Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s | |
| 57 | + * Cache-Control: no-cache</pre> | |
| 58 | + * become | |
| 59 | + * <pre>{... | |
| 60 | + * Date: "Sun, 26 May 2002 18:06:04 GMT", | |
| 61 | + * Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s", | |
| 62 | + * "Cache-Control": "no-cache", | |
| 63 | + * ...}</pre> | |
| 64 | + * It does no further checking or conversion. It does not parse dates. | |
| 65 | + * It does not do '%' transforms on URLs. | |
| 66 | + * @param string An HTTP header string. | |
| 67 | + * @return A JSONObject containing the elements and attributes | |
| 68 | + * of the XML string. | |
| 69 | + * @throws JSONException | |
| 70 | + */ | |
| 71 | + public static JSONObject toJSONObject(String string) throws JSONException { | |
| 72 | + JSONObject jo = new JSONObject(); | |
| 73 | + HTTPTokener x = new HTTPTokener(string); | |
| 74 | + String token; | |
| 75 | + | |
| 76 | + token = x.nextToken(); | |
| 77 | + if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { | |
| 78 | + | |
| 79 | +// Response | |
| 80 | + | |
| 81 | + jo.put("HTTP-Version", token); | |
| 82 | + jo.put("Status-Code", x.nextToken()); | |
| 83 | + jo.put("Reason-Phrase", x.nextTo('\0')); | |
| 84 | + x.next(); | |
| 85 | + | |
| 86 | + } else { | |
| 87 | + | |
| 88 | +// Request | |
| 89 | + | |
| 90 | + jo.put("Method", token); | |
| 91 | + jo.put("Request-URI", x.nextToken()); | |
| 92 | + jo.put("HTTP-Version", x.nextToken()); | |
| 93 | + } | |
| 94 | + | |
| 95 | +// Fields | |
| 96 | + | |
| 97 | + while (x.more()) { | |
| 98 | + String name = x.nextTo(':'); | |
| 99 | + x.next(':'); | |
| 100 | + jo.put(name, x.nextTo('\0')); | |
| 101 | + x.next(); | |
| 102 | + } | |
| 103 | + return jo; | |
| 104 | + } | |
| 105 | + | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Convert a JSONObject into an HTTP header. A request header must contain | |
| 109 | + * <pre>{ | |
| 110 | + * Method: "POST" (for example), | |
| 111 | + * "Request-URI": "/" (for example), | |
| 112 | + * "HTTP-Version": "HTTP/1.1" (for example) | |
| 113 | + * }</pre> | |
| 114 | + * A response header must contain | |
| 115 | + * <pre>{ | |
| 116 | + * "HTTP-Version": "HTTP/1.1" (for example), | |
| 117 | + * "Status-Code": "200" (for example), | |
| 118 | + * "Reason-Phrase": "OK" (for example) | |
| 119 | + * }</pre> | |
| 120 | + * Any other members of the JSONObject will be output as HTTP fields. | |
| 121 | + * The result will end with two CRLF pairs. | |
| 122 | + * @param jo A JSONObject | |
| 123 | + * @return An HTTP header string. | |
| 124 | + * @throws JSONException if the object does not contain enough | |
| 125 | + * information. | |
| 126 | + */ | |
| 127 | + public static String toString(JSONObject jo) throws JSONException { | |
| 128 | + StringBuilder sb = new StringBuilder(); | |
| 129 | + if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { | |
| 130 | + sb.append(jo.getString("HTTP-Version")); | |
| 131 | + sb.append(' '); | |
| 132 | + sb.append(jo.getString("Status-Code")); | |
| 133 | + sb.append(' '); | |
| 134 | + sb.append(jo.getString("Reason-Phrase")); | |
| 135 | + } else if (jo.has("Method") && jo.has("Request-URI")) { | |
| 136 | + sb.append(jo.getString("Method")); | |
| 137 | + sb.append(' '); | |
| 138 | + sb.append('"'); | |
| 139 | + sb.append(jo.getString("Request-URI")); | |
| 140 | + sb.append('"'); | |
| 141 | + sb.append(' '); | |
| 142 | + sb.append(jo.getString("HTTP-Version")); | |
| 143 | + } else { | |
| 144 | + throw new JSONException("Not enough material for an HTTP header."); | |
| 145 | + } | |
| 146 | + sb.append(CRLF); | |
| 147 | + // Don't use the new entrySet API to maintain Android support | |
| 148 | + for (final String key : jo.keySet()) { | |
| 149 | + String value = jo.optString(key); | |
| 150 | + if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && | |
| 151 | + !"Reason-Phrase".equals(key) && !"Method".equals(key) && | |
| 152 | + !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) { | |
| 153 | + sb.append(key); | |
| 154 | + sb.append(": "); | |
| 155 | + sb.append(jo.optString(key)); | |
| 156 | + sb.append(CRLF); | |
| 157 | + } | |
| 158 | + } | |
| 159 | + sb.append(CRLF); | |
| 160 | + return sb.toString(); | |
| 161 | + } | |
| 162 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/HTTPTokener.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * The HTTPTokener extends the JSONTokener to provide additional methods | |
| 29 | + * for the parsing of HTTP headers. | |
| 30 | + * @author JSON.org | |
| 31 | + * @version 2015-12-09 | |
| 32 | + */ | |
| 33 | +public class HTTPTokener extends JSONTokener { | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * Construct an HTTPTokener from a string. | |
| 37 | + * @param string A source string. | |
| 38 | + */ | |
| 39 | + public HTTPTokener(String string) { | |
| 40 | + super(string); | |
| 41 | + } | |
| 42 | + | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * Get the next token or string. This is used in parsing HTTP headers. | |
| 46 | + * @throws JSONException | |
| 47 | + * @return A String. | |
| 48 | + */ | |
| 49 | + public String nextToken() throws JSONException { | |
| 50 | + char c; | |
| 51 | + char q; | |
| 52 | + StringBuilder sb = new StringBuilder(); | |
| 53 | + do { | |
| 54 | + c = next(); | |
| 55 | + } while (Character.isWhitespace(c)); | |
| 56 | + if (c == '"' || c == '\'') { | |
| 57 | + q = c; | |
| 58 | + for (;;) { | |
| 59 | + c = next(); | |
| 60 | + if (c < ' ') { | |
| 61 | + throw syntaxError("Unterminated string."); | |
| 62 | + } | |
| 63 | + if (c == q) { | |
| 64 | + return sb.toString(); | |
| 65 | + } | |
| 66 | + sb.append(c); | |
| 67 | + } | |
| 68 | + } | |
| 69 | + for (;;) { | |
| 70 | + if (c == 0 || Character.isWhitespace(c)) { | |
| 71 | + return sb.toString(); | |
| 72 | + } | |
| 73 | + sb.append(c); | |
| 74 | + c = next(); | |
| 75 | + } | |
| 76 | + } | |
| 77 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONArray.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | + Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | + Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + of this software and associated documentation files (the "Software"), to deal | |
| 8 | + in the Software without restriction, including without limitation the rights | |
| 9 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + copies of the Software, and to permit persons to whom the Software is | |
| 11 | + furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | + The above copyright notice and this permission notice shall be included in all | |
| 14 | + copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | + The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | + SOFTWARE. | |
| 25 | + */ | |
| 26 | + | |
| 27 | +import java.io.IOException; | |
| 28 | +import java.io.StringWriter; | |
| 29 | +import java.io.Writer; | |
| 30 | +import java.lang.reflect.Array; | |
| 31 | +import java.math.BigDecimal; | |
| 32 | +import java.math.BigInteger; | |
| 33 | +import java.util.*; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * A JSONArray is an ordered sequence of values. Its external text form is a | |
| 37 | + * string wrapped in square brackets with commas separating the values. The | |
| 38 | + * internal form is an object having <code>get</code> and <code>opt</code> | |
| 39 | + * methods for accessing the values by index, and <code>put</code> methods for | |
| 40 | + * adding or replacing values. The values can be any of these types: | |
| 41 | + * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, | |
| 42 | + * <code>Number</code>, <code>String</code>, or the | |
| 43 | + * <code>JSONObject.NULL object</code>. | |
| 44 | + * <p> | |
| 45 | + * The constructor can convert a JSON text into a Java object. The | |
| 46 | + * <code>toString</code> method converts to JSON text. | |
| 47 | + * <p> | |
| 48 | + * A <code>get</code> method returns a value if one can be found, and throws an | |
| 49 | + * exception if one cannot be found. An <code>opt</code> method returns a | |
| 50 | + * default value instead of throwing an exception, and so is useful for | |
| 51 | + * obtaining optional values. | |
| 52 | + * <p> | |
| 53 | + * The generic <code>get()</code> and <code>opt()</code> methods return an | |
| 54 | + * object which you can cast or query for type. There are also typed | |
| 55 | + * <code>get</code> and <code>opt</code> methods that do type checking and type | |
| 56 | + * coercion for you. | |
| 57 | + * <p> | |
| 58 | + * The texts produced by the <code>toString</code> methods strictly conform to | |
| 59 | + * JSON syntax rules. The constructors are more forgiving in the texts they will | |
| 60 | + * accept: | |
| 61 | + * <ul> | |
| 62 | + * <li>An extra <code>,</code> <small>(comma)</small> may appear just | |
| 63 | + * before the closing bracket.</li> | |
| 64 | + * <li>The <code>null</code> value will be inserted when there is <code>,</code> | |
| 65 | + * <small>(comma)</small> elision.</li> | |
| 66 | + * <li>Strings may be quoted with <code>'</code> <small>(single | |
| 67 | + * quote)</small>.</li> | |
| 68 | + * <li>Strings do not need to be quoted at all if they do not begin with a quote | |
| 69 | + * or single quote, and if they do not contain leading or trailing spaces, and | |
| 70 | + * if they do not contain any of these characters: | |
| 71 | + * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and | |
| 72 | + * if they are not the reserved words <code>true</code>, <code>false</code>, or | |
| 73 | + * <code>null</code>.</li> | |
| 74 | + * </ul> | |
| 75 | + * | |
| 76 | + * @author JSON.org | |
| 77 | + * @version 2016-08/15 | |
| 78 | + */ | |
| 79 | +public class JSONArray implements Iterable<Object> { | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * The arrayList where the JSONArray's properties are kept. | |
| 83 | + */ | |
| 84 | + private final ArrayList<Object> myArrayList; | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Construct an empty JSONArray. | |
| 88 | + */ | |
| 89 | + public JSONArray() { | |
| 90 | + this.myArrayList = new ArrayList<Object>(); | |
| 91 | + } | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * Construct a JSONArray from a JSONTokener. | |
| 95 | + * | |
| 96 | + * @param x | |
| 97 | + * A JSONTokener | |
| 98 | + * @throws JSONException | |
| 99 | + * If there is a syntax error. | |
| 100 | + */ | |
| 101 | + public JSONArray(JSONTokener x) throws JSONException { | |
| 102 | + this(); | |
| 103 | + if (x.nextClean() != '[') { | |
| 104 | + throw x.syntaxError("A JSONArray text must start with '['"); | |
| 105 | + } | |
| 106 | + | |
| 107 | + char nextChar = x.nextClean(); | |
| 108 | + if (nextChar == 0) { | |
| 109 | + // array is unclosed. No ']' found, instead EOF | |
| 110 | + throw x.syntaxError("Expected a ',' or ']'"); | |
| 111 | + } | |
| 112 | + if (nextChar != ']') { | |
| 113 | + x.back(); | |
| 114 | + for (;;) { | |
| 115 | + if (x.nextClean() == ',') { | |
| 116 | + x.back(); | |
| 117 | + this.myArrayList.add(JSONObject.NULL); | |
| 118 | + } else { | |
| 119 | + x.back(); | |
| 120 | + this.myArrayList.add(x.nextValue()); | |
| 121 | + } | |
| 122 | + switch (x.nextClean()) { | |
| 123 | + case 0: | |
| 124 | + // array is unclosed. No ']' found, instead EOF | |
| 125 | + throw x.syntaxError("Expected a ',' or ']'"); | |
| 126 | + case ',': | |
| 127 | + nextChar = x.nextClean(); | |
| 128 | + if (nextChar == 0) { | |
| 129 | + // array is unclosed. No ']' found, instead EOF | |
| 130 | + throw x.syntaxError("Expected a ',' or ']'"); | |
| 131 | + } | |
| 132 | + if (nextChar == ']') { | |
| 133 | + return; | |
| 134 | + } | |
| 135 | + x.back(); | |
| 136 | + break; | |
| 137 | + case ']': | |
| 138 | + return; | |
| 139 | + default: | |
| 140 | + throw x.syntaxError("Expected a ',' or ']'"); | |
| 141 | + } | |
| 142 | + } | |
| 143 | + } | |
| 144 | + } | |
| 145 | + | |
| 146 | + /** | |
| 147 | + * Construct a JSONArray from a source JSON text. | |
| 148 | + * | |
| 149 | + * @param source | |
| 150 | + * A string that begins with <code>[</code> <small>(left | |
| 151 | + * bracket)</small> and ends with <code>]</code> | |
| 152 | + * <small>(right bracket)</small>. | |
| 153 | + * @throws JSONException | |
| 154 | + * If there is a syntax error. | |
| 155 | + */ | |
| 156 | + public JSONArray(String source) throws JSONException { | |
| 157 | + this(new JSONTokener(source)); | |
| 158 | + } | |
| 159 | + | |
| 160 | + /** | |
| 161 | + * Construct a JSONArray from a Collection. | |
| 162 | + * | |
| 163 | + * @param collection | |
| 164 | + * A Collection. | |
| 165 | + */ | |
| 166 | + public JSONArray(Collection<?> collection) { | |
| 167 | + if (collection == null) { | |
| 168 | + this.myArrayList = new ArrayList<Object>(); | |
| 169 | + } else { | |
| 170 | + this.myArrayList = new ArrayList<Object>(collection.size()); | |
| 171 | + for (Object o: collection){ | |
| 172 | + this.myArrayList.add(JSONObject.wrap(o)); | |
| 173 | + } | |
| 174 | + } | |
| 175 | + } | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * Construct a JSONArray from an array | |
| 179 | + * | |
| 180 | + * @throws JSONException | |
| 181 | + * If not an array. | |
| 182 | + */ | |
| 183 | + public JSONArray(Object array) throws JSONException { | |
| 184 | + this(); | |
| 185 | + if (array.getClass().isArray()) { | |
| 186 | + int length = Array.getLength(array); | |
| 187 | + this.myArrayList.ensureCapacity(length); | |
| 188 | + for (int i = 0; i < length; i += 1) { | |
| 189 | + this.put(JSONObject.wrap(Array.get(array, i))); | |
| 190 | + } | |
| 191 | + } else { | |
| 192 | + throw new JSONException( | |
| 193 | + "JSONArray initial value should be a string or collection or array."); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + | |
| 197 | + @Override | |
| 198 | + public Iterator<Object> iterator() { | |
| 199 | + return this.myArrayList.iterator(); | |
| 200 | + } | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * Get the object value associated with an index. | |
| 204 | + * | |
| 205 | + * @param index | |
| 206 | + * The index must be between 0 and length() - 1. | |
| 207 | + * @return An object value. | |
| 208 | + * @throws JSONException | |
| 209 | + * If there is no value for the index. | |
| 210 | + */ | |
| 211 | + public Object get(int index) throws JSONException { | |
| 212 | + Object object = this.opt(index); | |
| 213 | + if (object == null) { | |
| 214 | + throw new JSONException("JSONArray[" + index + "] not found."); | |
| 215 | + } | |
| 216 | + return object; | |
| 217 | + } | |
| 218 | + | |
| 219 | + /** | |
| 220 | + * Get the boolean value associated with an index. The string values "true" | |
| 221 | + * and "false" are converted to boolean. | |
| 222 | + * | |
| 223 | + * @param index | |
| 224 | + * The index must be between 0 and length() - 1. | |
| 225 | + * @return The truth. | |
| 226 | + * @throws JSONException | |
| 227 | + * If there is no value for the index or if the value is not | |
| 228 | + * convertible to boolean. | |
| 229 | + */ | |
| 230 | + public boolean getBoolean(int index) throws JSONException { | |
| 231 | + Object object = this.get(index); | |
| 232 | + if (object.equals(Boolean.FALSE) | |
| 233 | + || (object instanceof String && ((String) object) | |
| 234 | + .equalsIgnoreCase("false"))) { | |
| 235 | + return false; | |
| 236 | + } else if (object.equals(Boolean.TRUE) | |
| 237 | + || (object instanceof String && ((String) object) | |
| 238 | + .equalsIgnoreCase("true"))) { | |
| 239 | + return true; | |
| 240 | + } | |
| 241 | + throw new JSONException("JSONArray[" + index + "] is not a boolean."); | |
| 242 | + } | |
| 243 | + | |
| 244 | + /** | |
| 245 | + * Get the double value associated with an index. | |
| 246 | + * | |
| 247 | + * @param index | |
| 248 | + * The index must be between 0 and length() - 1. | |
| 249 | + * @return The value. | |
| 250 | + * @throws JSONException | |
| 251 | + * If the key is not found or if the value cannot be converted | |
| 252 | + * to a number. | |
| 253 | + */ | |
| 254 | + public double getDouble(int index) throws JSONException { | |
| 255 | + Object object = this.get(index); | |
| 256 | + try { | |
| 257 | + return object instanceof Number ? ((Number) object).doubleValue() | |
| 258 | + : Double.parseDouble((String) object); | |
| 259 | + } catch (Exception e) { | |
| 260 | + throw new JSONException("JSONArray[" + index + "] is not a number.", e); | |
| 261 | + } | |
| 262 | + } | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Get the float value associated with a key. | |
| 266 | + * | |
| 267 | + * @param index | |
| 268 | + * The index must be between 0 and length() - 1. | |
| 269 | + * @return The numeric value. | |
| 270 | + * @throws JSONException | |
| 271 | + * if the key is not found or if the value is not a Number | |
| 272 | + * object and cannot be converted to a number. | |
| 273 | + */ | |
| 274 | + public float getFloat(int index) throws JSONException { | |
| 275 | + Object object = this.get(index); | |
| 276 | + try { | |
| 277 | + return object instanceof Number ? ((Number) object).floatValue() | |
| 278 | + : Float.parseFloat(object.toString()); | |
| 279 | + } catch (Exception e) { | |
| 280 | + throw new JSONException("JSONArray[" + index | |
| 281 | + + "] is not a number.", e); | |
| 282 | + } | |
| 283 | + } | |
| 284 | + | |
| 285 | + /** | |
| 286 | + * Get the Number value associated with a key. | |
| 287 | + * | |
| 288 | + * @param index | |
| 289 | + * The index must be between 0 and length() - 1. | |
| 290 | + * @return The numeric value. | |
| 291 | + * @throws JSONException | |
| 292 | + * if the key is not found or if the value is not a Number | |
| 293 | + * object and cannot be converted to a number. | |
| 294 | + */ | |
| 295 | + public Number getNumber(int index) throws JSONException { | |
| 296 | + Object object = this.get(index); | |
| 297 | + try { | |
| 298 | + if (object instanceof Number) { | |
| 299 | + return (Number)object; | |
| 300 | + } | |
| 301 | + return JSONObject.stringToNumber(object.toString()); | |
| 302 | + } catch (Exception e) { | |
| 303 | + throw new JSONException("JSONArray[" + index + "] is not a number.", e); | |
| 304 | + } | |
| 305 | + } | |
| 306 | + | |
| 307 | + /** | |
| 308 | + * Get the enum value associated with an index. | |
| 309 | + * | |
| 310 | + * @param clazz | |
| 311 | + * The type of enum to retrieve. | |
| 312 | + * @param index | |
| 313 | + * The index must be between 0 and length() - 1. | |
| 314 | + * @return The enum value at the index location | |
| 315 | + * @throws JSONException | |
| 316 | + * if the key is not found or if the value cannot be converted | |
| 317 | + * to an enum. | |
| 318 | + */ | |
| 319 | + public <E extends Enum<E>> E getEnum(Class<E> clazz, int index) throws JSONException { | |
| 320 | + E val = optEnum(clazz, index); | |
| 321 | + if(val==null) { | |
| 322 | + // JSONException should really take a throwable argument. | |
| 323 | + // If it did, I would re-implement this with the Enum.valueOf | |
| 324 | + // method and place any thrown exception in the JSONException | |
| 325 | + throw new JSONException("JSONArray[" + index + "] is not an enum of type " | |
| 326 | + + JSONObject.quote(clazz.getSimpleName()) + "."); | |
| 327 | + } | |
| 328 | + return val; | |
| 329 | + } | |
| 330 | + | |
| 331 | + /** | |
| 332 | + * Get the BigDecimal value associated with an index. | |
| 333 | + * | |
| 334 | + * @param index | |
| 335 | + * The index must be between 0 and length() - 1. | |
| 336 | + * @return The value. | |
| 337 | + * @throws JSONException | |
| 338 | + * If the key is not found or if the value cannot be converted | |
| 339 | + * to a BigDecimal. | |
| 340 | + */ | |
| 341 | + public BigDecimal getBigDecimal (int index) throws JSONException { | |
| 342 | + Object object = this.get(index); | |
| 343 | + try { | |
| 344 | + return new BigDecimal(object.toString()); | |
| 345 | + } catch (Exception e) { | |
| 346 | + throw new JSONException("JSONArray[" + index + | |
| 347 | + "] could not convert to BigDecimal.", e); | |
| 348 | + } | |
| 349 | + } | |
| 350 | + | |
| 351 | + /** | |
| 352 | + * Get the BigInteger value associated with an index. | |
| 353 | + * | |
| 354 | + * @param index | |
| 355 | + * The index must be between 0 and length() - 1. | |
| 356 | + * @return The value. | |
| 357 | + * @throws JSONException | |
| 358 | + * If the key is not found or if the value cannot be converted | |
| 359 | + * to a BigInteger. | |
| 360 | + */ | |
| 361 | + public BigInteger getBigInteger (int index) throws JSONException { | |
| 362 | + Object object = this.get(index); | |
| 363 | + try { | |
| 364 | + return new BigInteger(object.toString()); | |
| 365 | + } catch (Exception e) { | |
| 366 | + throw new JSONException("JSONArray[" + index + | |
| 367 | + "] could not convert to BigInteger.", e); | |
| 368 | + } | |
| 369 | + } | |
| 370 | + | |
| 371 | + /** | |
| 372 | + * Get the int value associated with an index. | |
| 373 | + * | |
| 374 | + * @param index | |
| 375 | + * The index must be between 0 and length() - 1. | |
| 376 | + * @return The value. | |
| 377 | + * @throws JSONException | |
| 378 | + * If the key is not found or if the value is not a number. | |
| 379 | + */ | |
| 380 | + public int getInt(int index) throws JSONException { | |
| 381 | + Object object = this.get(index); | |
| 382 | + try { | |
| 383 | + return object instanceof Number ? ((Number) object).intValue() | |
| 384 | + : Integer.parseInt((String) object); | |
| 385 | + } catch (Exception e) { | |
| 386 | + throw new JSONException("JSONArray[" + index + "] is not a number.", e); | |
| 387 | + } | |
| 388 | + } | |
| 389 | + | |
| 390 | + /** | |
| 391 | + * Get the JSONArray associated with an index. | |
| 392 | + * | |
| 393 | + * @param index | |
| 394 | + * The index must be between 0 and length() - 1. | |
| 395 | + * @return A JSONArray value. | |
| 396 | + * @throws JSONException | |
| 397 | + * If there is no value for the index. or if the value is not a | |
| 398 | + * JSONArray | |
| 399 | + */ | |
| 400 | + public JSONArray getJSONArray(int index) throws JSONException { | |
| 401 | + Object object = this.get(index); | |
| 402 | + if (object instanceof JSONArray) { | |
| 403 | + return (JSONArray) object; | |
| 404 | + } | |
| 405 | + throw new JSONException("JSONArray[" + index + "] is not a JSONArray."); | |
| 406 | + } | |
| 407 | + | |
| 408 | + /** | |
| 409 | + * Get the JSONObject associated with an index. | |
| 410 | + * | |
| 411 | + * @param index | |
| 412 | + * subscript | |
| 413 | + * @return A JSONObject value. | |
| 414 | + * @throws JSONException | |
| 415 | + * If there is no value for the index or if the value is not a | |
| 416 | + * JSONObject | |
| 417 | + */ | |
| 418 | + public JSONObject getJSONObject(int index) throws JSONException { | |
| 419 | + Object object = this.get(index); | |
| 420 | + if (object instanceof JSONObject) { | |
| 421 | + return (JSONObject) object; | |
| 422 | + } | |
| 423 | + throw new JSONException("JSONArray[" + index + "] is not a JSONObject."); | |
| 424 | + } | |
| 425 | + | |
| 426 | + /** | |
| 427 | + * Get the long value associated with an index. | |
| 428 | + * | |
| 429 | + * @param index | |
| 430 | + * The index must be between 0 and length() - 1. | |
| 431 | + * @return The value. | |
| 432 | + * @throws JSONException | |
| 433 | + * If the key is not found or if the value cannot be converted | |
| 434 | + * to a number. | |
| 435 | + */ | |
| 436 | + public long getLong(int index) throws JSONException { | |
| 437 | + Object object = this.get(index); | |
| 438 | + try { | |
| 439 | + return object instanceof Number ? ((Number) object).longValue() | |
| 440 | + : Long.parseLong((String) object); | |
| 441 | + } catch (Exception e) { | |
| 442 | + throw new JSONException("JSONArray[" + index + "] is not a number.", e); | |
| 443 | + } | |
| 444 | + } | |
| 445 | + | |
| 446 | + /** | |
| 447 | + * Get the string associated with an index. | |
| 448 | + * | |
| 449 | + * @param index | |
| 450 | + * The index must be between 0 and length() - 1. | |
| 451 | + * @return A string value. | |
| 452 | + * @throws JSONException | |
| 453 | + * If there is no string value for the index. | |
| 454 | + */ | |
| 455 | + public String getString(int index) throws JSONException { | |
| 456 | + Object object = this.get(index); | |
| 457 | + if (object instanceof String) { | |
| 458 | + return (String) object; | |
| 459 | + } | |
| 460 | + throw new JSONException("JSONArray[" + index + "] not a string."); | |
| 461 | + } | |
| 462 | + | |
| 463 | + /** | |
| 464 | + * Determine if the value is null. | |
| 465 | + * | |
| 466 | + * @param index | |
| 467 | + * The index must be between 0 and length() - 1. | |
| 468 | + * @return true if the value at the index is null, or if there is no value. | |
| 469 | + */ | |
| 470 | + public boolean isNull(int index) { | |
| 471 | + return JSONObject.NULL.equals(this.opt(index)); | |
| 472 | + } | |
| 473 | + | |
| 474 | + /** | |
| 475 | + * Make a string from the contents of this JSONArray. The | |
| 476 | + * <code>separator</code> string is inserted between each element. Warning: | |
| 477 | + * This method assumes that the data structure is acyclical. | |
| 478 | + * | |
| 479 | + * @param separator | |
| 480 | + * A string that will be inserted between the elements. | |
| 481 | + * @return a string. | |
| 482 | + * @throws JSONException | |
| 483 | + * If the array contains an invalid number. | |
| 484 | + */ | |
| 485 | + public String join(String separator) throws JSONException { | |
| 486 | + int len = this.length(); | |
| 487 | + StringBuilder sb = new StringBuilder(); | |
| 488 | + | |
| 489 | + for (int i = 0; i < len; i += 1) { | |
| 490 | + if (i > 0) { | |
| 491 | + sb.append(separator); | |
| 492 | + } | |
| 493 | + sb.append(JSONObject.valueToString(this.myArrayList.get(i))); | |
| 494 | + } | |
| 495 | + return sb.toString(); | |
| 496 | + } | |
| 497 | + | |
| 498 | + /** | |
| 499 | + * Get the number of elements in the JSONArray, included nulls. | |
| 500 | + * | |
| 501 | + * @return The length (or size). | |
| 502 | + */ | |
| 503 | + public int length() { | |
| 504 | + return this.myArrayList.size(); | |
| 505 | + } | |
| 506 | + | |
| 507 | + /** | |
| 508 | + * Get the optional object value associated with an index. | |
| 509 | + * | |
| 510 | + * @param index | |
| 511 | + * The index must be between 0 and length() - 1. If not, null is returned. | |
| 512 | + * @return An object value, or null if there is no object at that index. | |
| 513 | + */ | |
| 514 | + public Object opt(int index) { | |
| 515 | + return (index < 0 || index >= this.length()) ? null : this.myArrayList | |
| 516 | + .get(index); | |
| 517 | + } | |
| 518 | + | |
| 519 | + /** | |
| 520 | + * Get the optional boolean value associated with an index. It returns false | |
| 521 | + * if there is no value at that index, or if the value is not Boolean.TRUE | |
| 522 | + * or the String "true". | |
| 523 | + * | |
| 524 | + * @param index | |
| 525 | + * The index must be between 0 and length() - 1. | |
| 526 | + * @return The truth. | |
| 527 | + */ | |
| 528 | + public boolean optBoolean(int index) { | |
| 529 | + return this.optBoolean(index, false); | |
| 530 | + } | |
| 531 | + | |
| 532 | + /** | |
| 533 | + * Get the optional boolean value associated with an index. It returns the | |
| 534 | + * defaultValue if there is no value at that index or if it is not a Boolean | |
| 535 | + * or the String "true" or "false" (case insensitive). | |
| 536 | + * | |
| 537 | + * @param index | |
| 538 | + * The index must be between 0 and length() - 1. | |
| 539 | + * @param defaultValue | |
| 540 | + * A boolean default. | |
| 541 | + * @return The truth. | |
| 542 | + */ | |
| 543 | + public boolean optBoolean(int index, boolean defaultValue) { | |
| 544 | + try { | |
| 545 | + return this.getBoolean(index); | |
| 546 | + } catch (Exception e) { | |
| 547 | + return defaultValue; | |
| 548 | + } | |
| 549 | + } | |
| 550 | + | |
| 551 | + /** | |
| 552 | + * Get the optional double value associated with an index. NaN is returned | |
| 553 | + * if there is no value for the index, or if the value is not a number and | |
| 554 | + * cannot be converted to a number. | |
| 555 | + * | |
| 556 | + * @param index | |
| 557 | + * The index must be between 0 and length() - 1. | |
| 558 | + * @return The value. | |
| 559 | + */ | |
| 560 | + public double optDouble(int index) { | |
| 561 | + return this.optDouble(index, Double.NaN); | |
| 562 | + } | |
| 563 | + | |
| 564 | + /** | |
| 565 | + * Get the optional double value associated with an index. The defaultValue | |
| 566 | + * is returned if there is no value for the index, or if the value is not a | |
| 567 | + * number and cannot be converted to a number. | |
| 568 | + * | |
| 569 | + * @param index | |
| 570 | + * subscript | |
| 571 | + * @param defaultValue | |
| 572 | + * The default value. | |
| 573 | + * @return The value. | |
| 574 | + */ | |
| 575 | + public double optDouble(int index, double defaultValue) { | |
| 576 | + Object val = this.opt(index); | |
| 577 | + if (JSONObject.NULL.equals(val)) { | |
| 578 | + return defaultValue; | |
| 579 | + } | |
| 580 | + if (val instanceof Number){ | |
| 581 | + return ((Number) val).doubleValue(); | |
| 582 | + } | |
| 583 | + if (val instanceof String) { | |
| 584 | + try { | |
| 585 | + return Double.parseDouble((String) val); | |
| 586 | + } catch (Exception e) { | |
| 587 | + return defaultValue; | |
| 588 | + } | |
| 589 | + } | |
| 590 | + return defaultValue; | |
| 591 | + } | |
| 592 | + | |
| 593 | + /** | |
| 594 | + * Get the optional float value associated with an index. NaN is returned | |
| 595 | + * if there is no value for the index, or if the value is not a number and | |
| 596 | + * cannot be converted to a number. | |
| 597 | + * | |
| 598 | + * @param index | |
| 599 | + * The index must be between 0 and length() - 1. | |
| 600 | + * @return The value. | |
| 601 | + */ | |
| 602 | + public float optFloat(int index) { | |
| 603 | + return this.optFloat(index, Float.NaN); | |
| 604 | + } | |
| 605 | + | |
| 606 | + /** | |
| 607 | + * Get the optional float value associated with an index. The defaultValue | |
| 608 | + * is returned if there is no value for the index, or if the value is not a | |
| 609 | + * number and cannot be converted to a number. | |
| 610 | + * | |
| 611 | + * @param index | |
| 612 | + * subscript | |
| 613 | + * @param defaultValue | |
| 614 | + * The default value. | |
| 615 | + * @return The value. | |
| 616 | + */ | |
| 617 | + public float optFloat(int index, float defaultValue) { | |
| 618 | + Object val = this.opt(index); | |
| 619 | + if (JSONObject.NULL.equals(val)) { | |
| 620 | + return defaultValue; | |
| 621 | + } | |
| 622 | + if (val instanceof Number){ | |
| 623 | + return ((Number) val).floatValue(); | |
| 624 | + } | |
| 625 | + if (val instanceof String) { | |
| 626 | + try { | |
| 627 | + return Float.parseFloat((String) val); | |
| 628 | + } catch (Exception e) { | |
| 629 | + return defaultValue; | |
| 630 | + } | |
| 631 | + } | |
| 632 | + return defaultValue; | |
| 633 | + } | |
| 634 | + | |
| 635 | + /** | |
| 636 | + * Get the optional int value associated with an index. Zero is returned if | |
| 637 | + * there is no value for the index, or if the value is not a number and | |
| 638 | + * cannot be converted to a number. | |
| 639 | + * | |
| 640 | + * @param index | |
| 641 | + * The index must be between 0 and length() - 1. | |
| 642 | + * @return The value. | |
| 643 | + */ | |
| 644 | + public int optInt(int index) { | |
| 645 | + return this.optInt(index, 0); | |
| 646 | + } | |
| 647 | + | |
| 648 | + /** | |
| 649 | + * Get the optional int value associated with an index. The defaultValue is | |
| 650 | + * returned if there is no value for the index, or if the value is not a | |
| 651 | + * number and cannot be converted to a number. | |
| 652 | + * | |
| 653 | + * @param index | |
| 654 | + * The index must be between 0 and length() - 1. | |
| 655 | + * @param defaultValue | |
| 656 | + * The default value. | |
| 657 | + * @return The value. | |
| 658 | + */ | |
| 659 | + public int optInt(int index, int defaultValue) { | |
| 660 | + Object val = this.opt(index); | |
| 661 | + if (JSONObject.NULL.equals(val)) { | |
| 662 | + return defaultValue; | |
| 663 | + } | |
| 664 | + if (val instanceof Number){ | |
| 665 | + return ((Number) val).intValue(); | |
| 666 | + } | |
| 667 | + | |
| 668 | + if (val instanceof String) { | |
| 669 | + try { | |
| 670 | + return new BigDecimal(val.toString()).intValue(); | |
| 671 | + } catch (Exception e) { | |
| 672 | + return defaultValue; | |
| 673 | + } | |
| 674 | + } | |
| 675 | + return defaultValue; | |
| 676 | + } | |
| 677 | + | |
| 678 | + /** | |
| 679 | + * Get the enum value associated with a key. | |
| 680 | + * | |
| 681 | + * @param clazz | |
| 682 | + * The type of enum to retrieve. | |
| 683 | + * @param index | |
| 684 | + * The index must be between 0 and length() - 1. | |
| 685 | + * @return The enum value at the index location or null if not found | |
| 686 | + */ | |
| 687 | + public <E extends Enum<E>> E optEnum(Class<E> clazz, int index) { | |
| 688 | + return this.optEnum(clazz, index, null); | |
| 689 | + } | |
| 690 | + | |
| 691 | + /** | |
| 692 | + * Get the enum value associated with a key. | |
| 693 | + * | |
| 694 | + * @param clazz | |
| 695 | + * The type of enum to retrieve. | |
| 696 | + * @param index | |
| 697 | + * The index must be between 0 and length() - 1. | |
| 698 | + * @param defaultValue | |
| 699 | + * The default in case the value is not found | |
| 700 | + * @return The enum value at the index location or defaultValue if | |
| 701 | + * the value is not found or cannot be assigned to clazz | |
| 702 | + */ | |
| 703 | + public <E extends Enum<E>> E optEnum(Class<E> clazz, int index, E defaultValue) { | |
| 704 | + try { | |
| 705 | + Object val = this.opt(index); | |
| 706 | + if (JSONObject.NULL.equals(val)) { | |
| 707 | + return defaultValue; | |
| 708 | + } | |
| 709 | + if (clazz.isAssignableFrom(val.getClass())) { | |
| 710 | + // we just checked it! | |
| 711 | + @SuppressWarnings("unchecked") | |
| 712 | + E myE = (E) val; | |
| 713 | + return myE; | |
| 714 | + } | |
| 715 | + return Enum.valueOf(clazz, val.toString()); | |
| 716 | + } catch (IllegalArgumentException e) { | |
| 717 | + return defaultValue; | |
| 718 | + } catch (NullPointerException e) { | |
| 719 | + return defaultValue; | |
| 720 | + } | |
| 721 | + } | |
| 722 | + | |
| 723 | + | |
| 724 | + /** | |
| 725 | + * Get the optional BigInteger value associated with an index. The | |
| 726 | + * defaultValue is returned if there is no value for the index, or if the | |
| 727 | + * value is not a number and cannot be converted to a number. | |
| 728 | + * | |
| 729 | + * @param index | |
| 730 | + * The index must be between 0 and length() - 1. | |
| 731 | + * @param defaultValue | |
| 732 | + * The default value. | |
| 733 | + * @return The value. | |
| 734 | + */ | |
| 735 | + public BigInteger optBigInteger(int index, BigInteger defaultValue) { | |
| 736 | + Object val = this.opt(index); | |
| 737 | + if (JSONObject.NULL.equals(val)) { | |
| 738 | + return defaultValue; | |
| 739 | + } | |
| 740 | + if (val instanceof BigInteger){ | |
| 741 | + return (BigInteger) val; | |
| 742 | + } | |
| 743 | + if (val instanceof BigDecimal){ | |
| 744 | + return ((BigDecimal) val).toBigInteger(); | |
| 745 | + } | |
| 746 | + if (val instanceof Double || val instanceof Float){ | |
| 747 | + return new BigDecimal(((Number) val).doubleValue()).toBigInteger(); | |
| 748 | + } | |
| 749 | + if (val instanceof Long || val instanceof Integer | |
| 750 | + || val instanceof Short || val instanceof Byte){ | |
| 751 | + return BigInteger.valueOf(((Number) val).longValue()); | |
| 752 | + } | |
| 753 | + try { | |
| 754 | + final String valStr = val.toString(); | |
| 755 | + if(JSONObject.isDecimalNotation(valStr)) { | |
| 756 | + return new BigDecimal(valStr).toBigInteger(); | |
| 757 | + } | |
| 758 | + return new BigInteger(valStr); | |
| 759 | + } catch (Exception e) { | |
| 760 | + return defaultValue; | |
| 761 | + } | |
| 762 | + } | |
| 763 | + | |
| 764 | + /** | |
| 765 | + * Get the optional BigDecimal value associated with an index. The | |
| 766 | + * defaultValue is returned if there is no value for the index, or if the | |
| 767 | + * value is not a number and cannot be converted to a number. | |
| 768 | + * | |
| 769 | + * @param index | |
| 770 | + * The index must be between 0 and length() - 1. | |
| 771 | + * @param defaultValue | |
| 772 | + * The default value. | |
| 773 | + * @return The value. | |
| 774 | + */ | |
| 775 | + public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { | |
| 776 | + Object val = this.opt(index); | |
| 777 | + if (JSONObject.NULL.equals(val)) { | |
| 778 | + return defaultValue; | |
| 779 | + } | |
| 780 | + if (val instanceof BigDecimal){ | |
| 781 | + return (BigDecimal) val; | |
| 782 | + } | |
| 783 | + if (val instanceof BigInteger){ | |
| 784 | + return new BigDecimal((BigInteger) val); | |
| 785 | + } | |
| 786 | + if (val instanceof Double || val instanceof Float){ | |
| 787 | + return new BigDecimal(((Number) val).doubleValue()); | |
| 788 | + } | |
| 789 | + if (val instanceof Long || val instanceof Integer | |
| 790 | + || val instanceof Short || val instanceof Byte){ | |
| 791 | + return new BigDecimal(((Number) val).longValue()); | |
| 792 | + } | |
| 793 | + try { | |
| 794 | + return new BigDecimal(val.toString()); | |
| 795 | + } catch (Exception e) { | |
| 796 | + return defaultValue; | |
| 797 | + } | |
| 798 | + } | |
| 799 | + | |
| 800 | + /** | |
| 801 | + * Get the optional JSONArray associated with an index. | |
| 802 | + * | |
| 803 | + * @param index | |
| 804 | + * subscript | |
| 805 | + * @return A JSONArray value, or null if the index has no value, or if the | |
| 806 | + * value is not a JSONArray. | |
| 807 | + */ | |
| 808 | + public JSONArray optJSONArray(int index) { | |
| 809 | + Object o = this.opt(index); | |
| 810 | + return o instanceof JSONArray ? (JSONArray) o : null; | |
| 811 | + } | |
| 812 | + | |
| 813 | + /** | |
| 814 | + * Get the optional JSONObject associated with an index. Null is returned if | |
| 815 | + * the key is not found, or null if the index has no value, or if the value | |
| 816 | + * is not a JSONObject. | |
| 817 | + * | |
| 818 | + * @param index | |
| 819 | + * The index must be between 0 and length() - 1. | |
| 820 | + * @return A JSONObject value. | |
| 821 | + */ | |
| 822 | + public JSONObject optJSONObject(int index) { | |
| 823 | + Object o = this.opt(index); | |
| 824 | + return o instanceof JSONObject ? (JSONObject) o : null; | |
| 825 | + } | |
| 826 | + | |
| 827 | + /** | |
| 828 | + * Get the optional long value associated with an index. Zero is returned if | |
| 829 | + * there is no value for the index, or if the value is not a number and | |
| 830 | + * cannot be converted to a number. | |
| 831 | + * | |
| 832 | + * @param index | |
| 833 | + * The index must be between 0 and length() - 1. | |
| 834 | + * @return The value. | |
| 835 | + */ | |
| 836 | + public long optLong(int index) { | |
| 837 | + return this.optLong(index, 0); | |
| 838 | + } | |
| 839 | + | |
| 840 | + /** | |
| 841 | + * Get the optional long value associated with an index. The defaultValue is | |
| 842 | + * returned if there is no value for the index, or if the value is not a | |
| 843 | + * number and cannot be converted to a number. | |
| 844 | + * | |
| 845 | + * @param index | |
| 846 | + * The index must be between 0 and length() - 1. | |
| 847 | + * @param defaultValue | |
| 848 | + * The default value. | |
| 849 | + * @return The value. | |
| 850 | + */ | |
| 851 | + public long optLong(int index, long defaultValue) { | |
| 852 | + Object val = this.opt(index); | |
| 853 | + if (JSONObject.NULL.equals(val)) { | |
| 854 | + return defaultValue; | |
| 855 | + } | |
| 856 | + if (val instanceof Number){ | |
| 857 | + return ((Number) val).longValue(); | |
| 858 | + } | |
| 859 | + | |
| 860 | + if (val instanceof String) { | |
| 861 | + try { | |
| 862 | + return new BigDecimal(val.toString()).longValue(); | |
| 863 | + } catch (Exception e) { | |
| 864 | + return defaultValue; | |
| 865 | + } | |
| 866 | + } | |
| 867 | + return defaultValue; | |
| 868 | + } | |
| 869 | + | |
| 870 | + /** | |
| 871 | + * Get an optional {@link Number} value associated with a key, or <code>null</code> | |
| 872 | + * if there is no such key or if the value is not a number. If the value is a string, | |
| 873 | + * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method | |
| 874 | + * would be used in cases where type coercion of the number value is unwanted. | |
| 875 | + * | |
| 876 | + * @param index | |
| 877 | + * The index must be between 0 and length() - 1. | |
| 878 | + * @return An object which is the value. | |
| 879 | + */ | |
| 880 | + public Number optNumber(int index) { | |
| 881 | + return this.optNumber(index, null); | |
| 882 | + } | |
| 883 | + | |
| 884 | + /** | |
| 885 | + * Get an optional {@link Number} value associated with a key, or the default if there | |
| 886 | + * is no such key or if the value is not a number. If the value is a string, | |
| 887 | + * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method | |
| 888 | + * would be used in cases where type coercion of the number value is unwanted. | |
| 889 | + * | |
| 890 | + * @param index | |
| 891 | + * The index must be between 0 and length() - 1. | |
| 892 | + * @param defaultValue | |
| 893 | + * The default. | |
| 894 | + * @return An object which is the value. | |
| 895 | + */ | |
| 896 | + public Number optNumber(int index, Number defaultValue) { | |
| 897 | + Object val = this.opt(index); | |
| 898 | + if (JSONObject.NULL.equals(val)) { | |
| 899 | + return defaultValue; | |
| 900 | + } | |
| 901 | + if (val instanceof Number){ | |
| 902 | + return (Number) val; | |
| 903 | + } | |
| 904 | + | |
| 905 | + if (val instanceof String) { | |
| 906 | + try { | |
| 907 | + return JSONObject.stringToNumber((String) val); | |
| 908 | + } catch (Exception e) { | |
| 909 | + return defaultValue; | |
| 910 | + } | |
| 911 | + } | |
| 912 | + return defaultValue; | |
| 913 | + } | |
| 914 | + | |
| 915 | + /** | |
| 916 | + * Get the optional string value associated with an index. It returns an | |
| 917 | + * empty string if there is no value at that index. If the value is not a | |
| 918 | + * string and is not null, then it is converted to a string. | |
| 919 | + * | |
| 920 | + * @param index | |
| 921 | + * The index must be between 0 and length() - 1. | |
| 922 | + * @return A String value. | |
| 923 | + */ | |
| 924 | + public String optString(int index) { | |
| 925 | + return this.optString(index, ""); | |
| 926 | + } | |
| 927 | + | |
| 928 | + /** | |
| 929 | + * Get the optional string associated with an index. The defaultValue is | |
| 930 | + * returned if the key is not found. | |
| 931 | + * | |
| 932 | + * @param index | |
| 933 | + * The index must be between 0 and length() - 1. | |
| 934 | + * @param defaultValue | |
| 935 | + * The default value. | |
| 936 | + * @return A String value. | |
| 937 | + */ | |
| 938 | + public String optString(int index, String defaultValue) { | |
| 939 | + Object object = this.opt(index); | |
| 940 | + return JSONObject.NULL.equals(object) ? defaultValue : object | |
| 941 | + .toString(); | |
| 942 | + } | |
| 943 | + | |
| 944 | + /** | |
| 945 | + * Append a boolean value. This increases the array's length by one. | |
| 946 | + * | |
| 947 | + * @param value | |
| 948 | + * A boolean value. | |
| 949 | + * @return this. | |
| 950 | + */ | |
| 951 | + public JSONArray put(boolean value) { | |
| 952 | + this.put(value ? Boolean.TRUE : Boolean.FALSE); | |
| 953 | + return this; | |
| 954 | + } | |
| 955 | + | |
| 956 | + /** | |
| 957 | + * Put a value in the JSONArray, where the value will be a JSONArray which | |
| 958 | + * is produced from a Collection. | |
| 959 | + * | |
| 960 | + * @param value | |
| 961 | + * A Collection value. | |
| 962 | + * @return this. | |
| 963 | + */ | |
| 964 | + public JSONArray put(Collection<?> value) { | |
| 965 | + this.put(new JSONArray(value)); | |
| 966 | + return this; | |
| 967 | + } | |
| 968 | + | |
| 969 | + /** | |
| 970 | + * Append a double value. This increases the array's length by one. | |
| 971 | + * | |
| 972 | + * @param value | |
| 973 | + * A double value. | |
| 974 | + * @throws JSONException | |
| 975 | + * if the value is not finite. | |
| 976 | + * @return this. | |
| 977 | + */ | |
| 978 | + public JSONArray put(double value) throws JSONException { | |
| 979 | + Double d = new Double(value); | |
| 980 | + JSONObject.testValidity(d); | |
| 981 | + this.put(d); | |
| 982 | + return this; | |
| 983 | + } | |
| 984 | + | |
| 985 | + /** | |
| 986 | + * Append an int value. This increases the array's length by one. | |
| 987 | + * | |
| 988 | + * @param value | |
| 989 | + * An int value. | |
| 990 | + * @return this. | |
| 991 | + */ | |
| 992 | + public JSONArray put(int value) { | |
| 993 | + this.put(new Integer(value)); | |
| 994 | + return this; | |
| 995 | + } | |
| 996 | + | |
| 997 | + /** | |
| 998 | + * Append an long value. This increases the array's length by one. | |
| 999 | + * | |
| 1000 | + * @param value | |
| 1001 | + * A long value. | |
| 1002 | + * @return this. | |
| 1003 | + */ | |
| 1004 | + public JSONArray put(long value) { | |
| 1005 | + this.put(new Long(value)); | |
| 1006 | + return this; | |
| 1007 | + } | |
| 1008 | + | |
| 1009 | + /** | |
| 1010 | + * Put a value in the JSONArray, where the value will be a JSONObject which | |
| 1011 | + * is produced from a Map. | |
| 1012 | + * | |
| 1013 | + * @param value | |
| 1014 | + * A Map value. | |
| 1015 | + * @return this. | |
| 1016 | + */ | |
| 1017 | + public JSONArray put(Map<?, ?> value) { | |
| 1018 | + this.put(new JSONObject(value)); | |
| 1019 | + return this; | |
| 1020 | + } | |
| 1021 | + | |
| 1022 | + /** | |
| 1023 | + * Append an object value. This increases the array's length by one. | |
| 1024 | + * | |
| 1025 | + * @param value | |
| 1026 | + * An object value. The value should be a Boolean, Double, | |
| 1027 | + * Integer, JSONArray, JSONObject, Long, or String, or the | |
| 1028 | + * JSONObject.NULL object. | |
| 1029 | + * @return this. | |
| 1030 | + */ | |
| 1031 | + public JSONArray put(Object value) { | |
| 1032 | + this.myArrayList.add(value); | |
| 1033 | + return this; | |
| 1034 | + } | |
| 1035 | + | |
| 1036 | + /** | |
| 1037 | + * Put or replace a boolean value in the JSONArray. If the index is greater | |
| 1038 | + * than the length of the JSONArray, then null elements will be added as | |
| 1039 | + * necessary to pad it out. | |
| 1040 | + * | |
| 1041 | + * @param index | |
| 1042 | + * The subscript. | |
| 1043 | + * @param value | |
| 1044 | + * A boolean value. | |
| 1045 | + * @return this. | |
| 1046 | + * @throws JSONException | |
| 1047 | + * If the index is negative. | |
| 1048 | + */ | |
| 1049 | + public JSONArray put(int index, boolean value) throws JSONException { | |
| 1050 | + this.put(index, value ? Boolean.TRUE : Boolean.FALSE); | |
| 1051 | + return this; | |
| 1052 | + } | |
| 1053 | + | |
| 1054 | + /** | |
| 1055 | + * Put a value in the JSONArray, where the value will be a JSONArray which | |
| 1056 | + * is produced from a Collection. | |
| 1057 | + * | |
| 1058 | + * @param index | |
| 1059 | + * The subscript. | |
| 1060 | + * @param value | |
| 1061 | + * A Collection value. | |
| 1062 | + * @return this. | |
| 1063 | + * @throws JSONException | |
| 1064 | + * If the index is negative or if the value is not finite. | |
| 1065 | + */ | |
| 1066 | + public JSONArray put(int index, Collection<?> value) throws JSONException { | |
| 1067 | + this.put(index, new JSONArray(value)); | |
| 1068 | + return this; | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + /** | |
| 1072 | + * Put or replace a double value. If the index is greater than the length of | |
| 1073 | + * the JSONArray, then null elements will be added as necessary to pad it | |
| 1074 | + * out. | |
| 1075 | + * | |
| 1076 | + * @param index | |
| 1077 | + * The subscript. | |
| 1078 | + * @param value | |
| 1079 | + * A double value. | |
| 1080 | + * @return this. | |
| 1081 | + * @throws JSONException | |
| 1082 | + * If the index is negative or if the value is not finite. | |
| 1083 | + */ | |
| 1084 | + public JSONArray put(int index, double value) throws JSONException { | |
| 1085 | + this.put(index, new Double(value)); | |
| 1086 | + return this; | |
| 1087 | + } | |
| 1088 | + | |
| 1089 | + /** | |
| 1090 | + * Put or replace an int value. If the index is greater than the length of | |
| 1091 | + * the JSONArray, then null elements will be added as necessary to pad it | |
| 1092 | + * out. | |
| 1093 | + * | |
| 1094 | + * @param index | |
| 1095 | + * The subscript. | |
| 1096 | + * @param value | |
| 1097 | + * An int value. | |
| 1098 | + * @return this. | |
| 1099 | + * @throws JSONException | |
| 1100 | + * If the index is negative. | |
| 1101 | + */ | |
| 1102 | + public JSONArray put(int index, int value) throws JSONException { | |
| 1103 | + this.put(index, new Integer(value)); | |
| 1104 | + return this; | |
| 1105 | + } | |
| 1106 | + | |
| 1107 | + /** | |
| 1108 | + * Put or replace a long value. If the index is greater than the length of | |
| 1109 | + * the JSONArray, then null elements will be added as necessary to pad it | |
| 1110 | + * out. | |
| 1111 | + * | |
| 1112 | + * @param index | |
| 1113 | + * The subscript. | |
| 1114 | + * @param value | |
| 1115 | + * A long value. | |
| 1116 | + * @return this. | |
| 1117 | + * @throws JSONException | |
| 1118 | + * If the index is negative. | |
| 1119 | + */ | |
| 1120 | + public JSONArray put(int index, long value) throws JSONException { | |
| 1121 | + this.put(index, new Long(value)); | |
| 1122 | + return this; | |
| 1123 | + } | |
| 1124 | + | |
| 1125 | + /** | |
| 1126 | + * Put a value in the JSONArray, where the value will be a JSONObject that | |
| 1127 | + * is produced from a Map. | |
| 1128 | + * | |
| 1129 | + * @param index | |
| 1130 | + * The subscript. | |
| 1131 | + * @param value | |
| 1132 | + * The Map value. | |
| 1133 | + * @return this. | |
| 1134 | + * @throws JSONException | |
| 1135 | + * If the index is negative or if the the value is an invalid | |
| 1136 | + * number. | |
| 1137 | + */ | |
| 1138 | + public JSONArray put(int index, Map<?, ?> value) throws JSONException { | |
| 1139 | + this.put(index, new JSONObject(value)); | |
| 1140 | + return this; | |
| 1141 | + } | |
| 1142 | + | |
| 1143 | + /** | |
| 1144 | + * Put or replace an object value in the JSONArray. If the index is greater | |
| 1145 | + * than the length of the JSONArray, then null elements will be added as | |
| 1146 | + * necessary to pad it out. | |
| 1147 | + * | |
| 1148 | + * @param index | |
| 1149 | + * The subscript. | |
| 1150 | + * @param value | |
| 1151 | + * The value to put into the array. The value should be a | |
| 1152 | + * Boolean, Double, Integer, JSONArray, JSONObject, Long, or | |
| 1153 | + * String, or the JSONObject.NULL object. | |
| 1154 | + * @return this. | |
| 1155 | + * @throws JSONException | |
| 1156 | + * If the index is negative or if the the value is an invalid | |
| 1157 | + * number. | |
| 1158 | + */ | |
| 1159 | + public JSONArray put(int index, Object value) throws JSONException { | |
| 1160 | + JSONObject.testValidity(value); | |
| 1161 | + if (index < 0) { | |
| 1162 | + throw new JSONException("JSONArray[" + index + "] not found."); | |
| 1163 | + } | |
| 1164 | + if (index < this.length()) { | |
| 1165 | + this.myArrayList.set(index, value); | |
| 1166 | + } else if(index == this.length()){ | |
| 1167 | + // simple append | |
| 1168 | + this.put(value); | |
| 1169 | + } else { | |
| 1170 | + // if we are inserting past the length, we want to grow the array all at once | |
| 1171 | + // instead of incrementally. | |
| 1172 | + this.myArrayList.ensureCapacity(index + 1); | |
| 1173 | + while (index != this.length()) { | |
| 1174 | + this.put(JSONObject.NULL); | |
| 1175 | + } | |
| 1176 | + this.put(value); | |
| 1177 | + } | |
| 1178 | + return this; | |
| 1179 | + } | |
| 1180 | + | |
| 1181 | + /** | |
| 1182 | + * Creates a JSONPointer using an initialization string and tries to | |
| 1183 | + * match it to an item within this JSONArray. For example, given a | |
| 1184 | + * JSONArray initialized with this document: | |
| 1185 | + * <pre> | |
| 1186 | + * [ | |
| 1187 | + * {"b":"c"} | |
| 1188 | + * ] | |
| 1189 | + * </pre> | |
| 1190 | + * and this JSONPointer string: | |
| 1191 | + * <pre> | |
| 1192 | + * "/0/b" | |
| 1193 | + * </pre> | |
| 1194 | + * Then this method will return the String "c" | |
| 1195 | + * A JSONPointerException may be thrown from code called by this method. | |
| 1196 | + * | |
| 1197 | + * @param jsonPointer string that can be used to create a JSONPointer | |
| 1198 | + * @return the item matched by the JSONPointer, otherwise null | |
| 1199 | + */ | |
| 1200 | + public Object query(String jsonPointer) { | |
| 1201 | + return query(new JSONPointer(jsonPointer)); | |
| 1202 | + } | |
| 1203 | + | |
| 1204 | + /** | |
| 1205 | + * Uses a uaer initialized JSONPointer and tries to | |
| 1206 | + * match it to an item whithin this JSONArray. For example, given a | |
| 1207 | + * JSONArray initialized with this document: | |
| 1208 | + * <pre> | |
| 1209 | + * [ | |
| 1210 | + * {"b":"c"} | |
| 1211 | + * ] | |
| 1212 | + * </pre> | |
| 1213 | + * and this JSONPointer: | |
| 1214 | + * <pre> | |
| 1215 | + * "/0/b" | |
| 1216 | + * </pre> | |
| 1217 | + * Then this method will return the String "c" | |
| 1218 | + * A JSONPointerException may be thrown from code called by this method. | |
| 1219 | + * | |
| 1220 | + * @param jsonPointer string that can be used to create a JSONPointer | |
| 1221 | + * @return the item matched by the JSONPointer, otherwise null | |
| 1222 | + */ | |
| 1223 | + public Object query(JSONPointer jsonPointer) { | |
| 1224 | + return jsonPointer.queryFrom(this); | |
| 1225 | + } | |
| 1226 | + | |
| 1227 | + /** | |
| 1228 | + * Queries and returns a value from this object using {@code jsonPointer}, or | |
| 1229 | + * returns null if the query fails due to a missing key. | |
| 1230 | + * | |
| 1231 | + * @param jsonPointer the string representation of the JSON pointer | |
| 1232 | + * @return the queried value or {@code null} | |
| 1233 | + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax | |
| 1234 | + */ | |
| 1235 | + public Object optQuery(String jsonPointer) { | |
| 1236 | + return optQuery(new JSONPointer(jsonPointer)); | |
| 1237 | + } | |
| 1238 | + | |
| 1239 | + /** | |
| 1240 | + * Queries and returns a value from this object using {@code jsonPointer}, or | |
| 1241 | + * returns null if the query fails due to a missing key. | |
| 1242 | + * | |
| 1243 | + * @param jsonPointer The JSON pointer | |
| 1244 | + * @return the queried value or {@code null} | |
| 1245 | + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax | |
| 1246 | + */ | |
| 1247 | + public Object optQuery(JSONPointer jsonPointer) { | |
| 1248 | + try { | |
| 1249 | + return jsonPointer.queryFrom(this); | |
| 1250 | + } catch (JSONPointerException e) { | |
| 1251 | + return null; | |
| 1252 | + } | |
| 1253 | + } | |
| 1254 | + | |
| 1255 | + /** | |
| 1256 | + * Remove an index and close the hole. | |
| 1257 | + * | |
| 1258 | + * @param index | |
| 1259 | + * The index of the element to be removed. | |
| 1260 | + * @return The value that was associated with the index, or null if there | |
| 1261 | + * was no value. | |
| 1262 | + */ | |
| 1263 | + public Object remove(int index) { | |
| 1264 | + return index >= 0 && index < this.length() | |
| 1265 | + ? this.myArrayList.remove(index) | |
| 1266 | + : null; | |
| 1267 | + } | |
| 1268 | + | |
| 1269 | + /** | |
| 1270 | + * Determine if two JSONArrays are similar. | |
| 1271 | + * They must contain similar sequences. | |
| 1272 | + * | |
| 1273 | + * @param other The other JSONArray | |
| 1274 | + * @return true if they are equal | |
| 1275 | + */ | |
| 1276 | + public boolean similar(Object other) { | |
| 1277 | + if (!(other instanceof JSONArray)) { | |
| 1278 | + return false; | |
| 1279 | + } | |
| 1280 | + int len = this.length(); | |
| 1281 | + if (len != ((JSONArray)other).length()) { | |
| 1282 | + return false; | |
| 1283 | + } | |
| 1284 | + for (int i = 0; i < len; i += 1) { | |
| 1285 | + Object valueThis = this.myArrayList.get(i); | |
| 1286 | + Object valueOther = ((JSONArray)other).myArrayList.get(i); | |
| 1287 | + if(valueThis == valueOther) { | |
| 1288 | + continue; | |
| 1289 | + } | |
| 1290 | + if(valueThis == null) { | |
| 1291 | + return false; | |
| 1292 | + } | |
| 1293 | + if (valueThis instanceof JSONObject) { | |
| 1294 | + if (!((JSONObject)valueThis).similar(valueOther)) { | |
| 1295 | + return false; | |
| 1296 | + } | |
| 1297 | + } else if (valueThis instanceof JSONArray) { | |
| 1298 | + if (!((JSONArray)valueThis).similar(valueOther)) { | |
| 1299 | + return false; | |
| 1300 | + } | |
| 1301 | + } else if (!valueThis.equals(valueOther)) { | |
| 1302 | + return false; | |
| 1303 | + } | |
| 1304 | + } | |
| 1305 | + return true; | |
| 1306 | + } | |
| 1307 | + | |
| 1308 | + /** | |
| 1309 | + * Produce a JSONObject by combining a JSONArray of names with the values of | |
| 1310 | + * this JSONArray. | |
| 1311 | + * | |
| 1312 | + * @param names | |
| 1313 | + * A JSONArray containing a list of key strings. These will be | |
| 1314 | + * paired with the values. | |
| 1315 | + * @return A JSONObject, or null if there are no names or if this JSONArray | |
| 1316 | + * has no values. | |
| 1317 | + * @throws JSONException | |
| 1318 | + * If any of the names are null. | |
| 1319 | + */ | |
| 1320 | + public JSONObject toJSONObject(JSONArray names) throws JSONException { | |
| 1321 | + if (names == null || names.length() == 0 || this.length() == 0) { | |
| 1322 | + return null; | |
| 1323 | + } | |
| 1324 | + JSONObject jo = new JSONObject(names.length()); | |
| 1325 | + for (int i = 0; i < names.length(); i += 1) { | |
| 1326 | + jo.put(names.getString(i), this.opt(i)); | |
| 1327 | + } | |
| 1328 | + return jo; | |
| 1329 | + } | |
| 1330 | + | |
| 1331 | + /** | |
| 1332 | + * Make a JSON text of this JSONArray. For compactness, no unnecessary | |
| 1333 | + * whitespace is added. If it is not possible to produce a syntactically | |
| 1334 | + * correct JSON text then null will be returned instead. This could occur if | |
| 1335 | + * the array contains an invalid number. | |
| 1336 | + * <p><b> | |
| 1337 | + * Warning: This method assumes that the data structure is acyclical. | |
| 1338 | + * </b> | |
| 1339 | + * | |
| 1340 | + * @return a printable, displayable, transmittable representation of the | |
| 1341 | + * array. | |
| 1342 | + */ | |
| 1343 | + @Override | |
| 1344 | + public String toString() { | |
| 1345 | + try { | |
| 1346 | + return this.toString(0); | |
| 1347 | + } catch (Exception e) { | |
| 1348 | + return null; | |
| 1349 | + } | |
| 1350 | + } | |
| 1351 | + | |
| 1352 | + /** | |
| 1353 | + * Make a pretty-printed JSON text of this JSONArray. | |
| 1354 | + * | |
| 1355 | + * <p>If <code>indentFactor > 0</code> and the {@link JSONArray} has only | |
| 1356 | + * one element, then the array will be output on a single line: | |
| 1357 | + * <pre>{@code [1]}</pre> | |
| 1358 | + * | |
| 1359 | + * <p>If an array has 2 or more elements, then it will be output across | |
| 1360 | + * multiple lines: <pre>{@code | |
| 1361 | + * [ | |
| 1362 | + * 1, | |
| 1363 | + * "value 2", | |
| 1364 | + * 3 | |
| 1365 | + * ] | |
| 1366 | + * }</pre> | |
| 1367 | + * <p><b> | |
| 1368 | + * Warning: This method assumes that the data structure is acyclical. | |
| 1369 | + * </b> | |
| 1370 | + * | |
| 1371 | + * @param indentFactor | |
| 1372 | + * The number of spaces to add to each level of indentation. | |
| 1373 | + * @return a printable, displayable, transmittable representation of the | |
| 1374 | + * object, beginning with <code>[</code> <small>(left | |
| 1375 | + * bracket)</small> and ending with <code>]</code> | |
| 1376 | + * <small>(right bracket)</small>. | |
| 1377 | + * @throws JSONException | |
| 1378 | + */ | |
| 1379 | + public String toString(int indentFactor) throws JSONException { | |
| 1380 | + StringWriter sw = new StringWriter(); | |
| 1381 | + synchronized (sw.getBuffer()) { | |
| 1382 | + return this.write(sw, indentFactor, 0).toString(); | |
| 1383 | + } | |
| 1384 | + } | |
| 1385 | + | |
| 1386 | + /** | |
| 1387 | + * Write the contents of the JSONArray as JSON text to a writer. For | |
| 1388 | + * compactness, no whitespace is added. | |
| 1389 | + * <p><b> | |
| 1390 | + * Warning: This method assumes that the data structure is acyclical. | |
| 1391 | + *</b> | |
| 1392 | + * | |
| 1393 | + * @return The writer. | |
| 1394 | + * @throws JSONException | |
| 1395 | + */ | |
| 1396 | + public Writer write(Writer writer) throws JSONException { | |
| 1397 | + return this.write(writer, 0, 0); | |
| 1398 | + } | |
| 1399 | + | |
| 1400 | + /** | |
| 1401 | + * Write the contents of the JSONArray as JSON text to a writer. | |
| 1402 | + * | |
| 1403 | + * <p>If <code>indentFactor > 0</code> and the {@link JSONArray} has only | |
| 1404 | + * one element, then the array will be output on a single line: | |
| 1405 | + * <pre>{@code [1]}</pre> | |
| 1406 | + * | |
| 1407 | + * <p>If an array has 2 or more elements, then it will be output across | |
| 1408 | + * multiple lines: <pre>{@code | |
| 1409 | + * [ | |
| 1410 | + * 1, | |
| 1411 | + * "value 2", | |
| 1412 | + * 3 | |
| 1413 | + * ] | |
| 1414 | + * }</pre> | |
| 1415 | + * <p><b> | |
| 1416 | + * Warning: This method assumes that the data structure is acyclical. | |
| 1417 | + * </b> | |
| 1418 | + * | |
| 1419 | + * @param writer | |
| 1420 | + * Writes the serialized JSON | |
| 1421 | + * @param indentFactor | |
| 1422 | + * The number of spaces to add to each level of indentation. | |
| 1423 | + * @param indent | |
| 1424 | + * The indentation of the top level. | |
| 1425 | + * @return The writer. | |
| 1426 | + * @throws JSONException | |
| 1427 | + */ | |
| 1428 | + public Writer write(Writer writer, int indentFactor, int indent) | |
| 1429 | + throws JSONException { | |
| 1430 | + try { | |
| 1431 | + boolean commanate = false; | |
| 1432 | + int length = this.length(); | |
| 1433 | + writer.write('['); | |
| 1434 | + | |
| 1435 | + if (length == 1) { | |
| 1436 | + try { | |
| 1437 | + JSONObject.writeValue(writer, this.myArrayList.get(0), | |
| 1438 | + indentFactor, indent); | |
| 1439 | + } catch (Exception e) { | |
| 1440 | + throw new JSONException("Unable to write JSONArray value at index: 0", e); | |
| 1441 | + } | |
| 1442 | + } else if (length != 0) { | |
| 1443 | + final int newindent = indent + indentFactor; | |
| 1444 | + | |
| 1445 | + for (int i = 0; i < length; i += 1) { | |
| 1446 | + if (commanate) { | |
| 1447 | + writer.write(','); | |
| 1448 | + } | |
| 1449 | + if (indentFactor > 0) { | |
| 1450 | + writer.write('\n'); | |
| 1451 | + } | |
| 1452 | + JSONObject.indent(writer, newindent); | |
| 1453 | + try { | |
| 1454 | + JSONObject.writeValue(writer, this.myArrayList.get(i), | |
| 1455 | + indentFactor, newindent); | |
| 1456 | + } catch (Exception e) { | |
| 1457 | + throw new JSONException("Unable to write JSONArray value at index: " + i, e); | |
| 1458 | + } | |
| 1459 | + commanate = true; | |
| 1460 | + } | |
| 1461 | + if (indentFactor > 0) { | |
| 1462 | + writer.write('\n'); | |
| 1463 | + } | |
| 1464 | + JSONObject.indent(writer, indent); | |
| 1465 | + } | |
| 1466 | + writer.write(']'); | |
| 1467 | + return writer; | |
| 1468 | + } catch (IOException e) { | |
| 1469 | + throw new JSONException(e); | |
| 1470 | + } | |
| 1471 | + } | |
| 1472 | + | |
| 1473 | + /** | |
| 1474 | + * Returns a java.util.List containing all of the elements in this array. | |
| 1475 | + * If an element in the array is a JSONArray or JSONObject it will also | |
| 1476 | + * be converted. | |
| 1477 | + * <p> | |
| 1478 | + * Warning: This method assumes that the data structure is acyclical. | |
| 1479 | + * | |
| 1480 | + * @return a java.util.List containing the elements of this array | |
| 1481 | + */ | |
| 1482 | + public List<Object> toList() { | |
| 1483 | + List<Object> results = new ArrayList<Object>(this.myArrayList.size()); | |
| 1484 | + for (Object element : this.myArrayList) { | |
| 1485 | + if (element == null || JSONObject.NULL.equals(element)) { | |
| 1486 | + results.add(null); | |
| 1487 | + } else if (element instanceof JSONArray) { | |
| 1488 | + results.add(((JSONArray) element).toList()); | |
| 1489 | + } else if (element instanceof JSONObject) { | |
| 1490 | + results.add(((JSONObject) element).toMap()); | |
| 1491 | + } else { | |
| 1492 | + results.add(element); | |
| 1493 | + } | |
| 1494 | + } | |
| 1495 | + return results; | |
| 1496 | + } | |
| 1497 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONException.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * The JSONException is thrown by the JSON.org classes when things are amiss. | |
| 5 | + * | |
| 6 | + * @author JSON.org | |
| 7 | + * @version 2015-12-09 | |
| 8 | + */ | |
| 9 | +public class JSONException extends RuntimeException { | |
| 10 | + /** Serialization ID */ | |
| 11 | + private static final long serialVersionUID = 0; | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * Constructs a JSONException with an explanatory message. | |
| 15 | + * | |
| 16 | + * @param message | |
| 17 | + * Detail about the reason for the exception. | |
| 18 | + */ | |
| 19 | + public JSONException(final String message) { | |
| 20 | + super(message); | |
| 21 | + } | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * Constructs a JSONException with an explanatory message and cause. | |
| 25 | + * | |
| 26 | + * @param message | |
| 27 | + * Detail about the reason for the exception. | |
| 28 | + * @param cause | |
| 29 | + * The cause. | |
| 30 | + */ | |
| 31 | + public JSONException(final String message, final Throwable cause) { | |
| 32 | + super(message, cause); | |
| 33 | + } | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * Constructs a new JSONException with the specified cause. | |
| 37 | + * | |
| 38 | + * @param cause | |
| 39 | + * The cause. | |
| 40 | + */ | |
| 41 | + public JSONException(final Throwable cause) { | |
| 42 | + super(cause.getMessage(), cause); | |
| 43 | + } | |
| 44 | + | |
| 45 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONML.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2008 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * This provides static methods to convert an XML text into a JSONArray or | |
| 29 | + * JSONObject, and to covert a JSONArray or JSONObject into an XML text using | |
| 30 | + * the JsonML transform. | |
| 31 | + * | |
| 32 | + * @author JSON.org | |
| 33 | + * @version 2016-01-30 | |
| 34 | + */ | |
| 35 | +public class JSONML { | |
| 36 | + /** | |
| 37 | + * Parse XML values and store them in a JSONArray. | |
| 38 | + * @param x The XMLTokener containing the source string. | |
| 39 | + * @param arrayForm true if array form, false if object form. | |
| 40 | + * @param ja The JSONArray that is containing the current tag or null | |
| 41 | + * if we are at the outermost level. | |
| 42 | + * @param keepStrings Don't type-convert text nodes and attribute values | |
| 43 | + * @return A JSONArray if the value is the outermost tag, otherwise null. | |
| 44 | + * @throws JSONException | |
| 45 | + */ | |
| 46 | + private static Object parse( | |
| 47 | + XMLTokener x, | |
| 48 | + boolean arrayForm, | |
| 49 | + JSONArray ja, | |
| 50 | + boolean keepStrings | |
| 51 | + ) throws JSONException { | |
| 52 | + String attribute; | |
| 53 | + char c; | |
| 54 | + String closeTag = null; | |
| 55 | + int i; | |
| 56 | + JSONArray newja = null; | |
| 57 | + JSONObject newjo = null; | |
| 58 | + Object token; | |
| 59 | + String tagName = null; | |
| 60 | + | |
| 61 | +// Test for and skip past these forms: | |
| 62 | +// <!-- ... --> | |
| 63 | +// <![ ... ]]> | |
| 64 | +// <! ... > | |
| 65 | +// <? ... ?> | |
| 66 | + | |
| 67 | + while (true) { | |
| 68 | + if (!x.more()) { | |
| 69 | + throw x.syntaxError("Bad XML"); | |
| 70 | + } | |
| 71 | + token = x.nextContent(); | |
| 72 | + if (token == XML.LT) { | |
| 73 | + token = x.nextToken(); | |
| 74 | + if (token instanceof Character) { | |
| 75 | + if (token == XML.SLASH) { | |
| 76 | + | |
| 77 | +// Close tag </ | |
| 78 | + | |
| 79 | + token = x.nextToken(); | |
| 80 | + if (!(token instanceof String)) { | |
| 81 | + throw new JSONException( | |
| 82 | + "Expected a closing name instead of '" + | |
| 83 | + token + "'."); | |
| 84 | + } | |
| 85 | + if (x.nextToken() != XML.GT) { | |
| 86 | + throw x.syntaxError("Misshaped close tag"); | |
| 87 | + } | |
| 88 | + return token; | |
| 89 | + } else if (token == XML.BANG) { | |
| 90 | + | |
| 91 | +// <! | |
| 92 | + | |
| 93 | + c = x.next(); | |
| 94 | + if (c == '-') { | |
| 95 | + if (x.next() == '-') { | |
| 96 | + x.skipPast("-->"); | |
| 97 | + } else { | |
| 98 | + x.back(); | |
| 99 | + } | |
| 100 | + } else if (c == '[') { | |
| 101 | + token = x.nextToken(); | |
| 102 | + if (token.equals("CDATA") && x.next() == '[') { | |
| 103 | + if (ja != null) { | |
| 104 | + ja.put(x.nextCDATA()); | |
| 105 | + } | |
| 106 | + } else { | |
| 107 | + throw x.syntaxError("Expected 'CDATA['"); | |
| 108 | + } | |
| 109 | + } else { | |
| 110 | + i = 1; | |
| 111 | + do { | |
| 112 | + token = x.nextMeta(); | |
| 113 | + if (token == null) { | |
| 114 | + throw x.syntaxError("Missing '>' after '<!'."); | |
| 115 | + } else if (token == XML.LT) { | |
| 116 | + i += 1; | |
| 117 | + } else if (token == XML.GT) { | |
| 118 | + i -= 1; | |
| 119 | + } | |
| 120 | + } while (i > 0); | |
| 121 | + } | |
| 122 | + } else if (token == XML.QUEST) { | |
| 123 | + | |
| 124 | +// <? | |
| 125 | + | |
| 126 | + x.skipPast("?>"); | |
| 127 | + } else { | |
| 128 | + throw x.syntaxError("Misshaped tag"); | |
| 129 | + } | |
| 130 | + | |
| 131 | +// Open tag < | |
| 132 | + | |
| 133 | + } else { | |
| 134 | + if (!(token instanceof String)) { | |
| 135 | + throw x.syntaxError("Bad tagName '" + token + "'."); | |
| 136 | + } | |
| 137 | + tagName = (String)token; | |
| 138 | + newja = new JSONArray(); | |
| 139 | + newjo = new JSONObject(); | |
| 140 | + if (arrayForm) { | |
| 141 | + newja.put(tagName); | |
| 142 | + if (ja != null) { | |
| 143 | + ja.put(newja); | |
| 144 | + } | |
| 145 | + } else { | |
| 146 | + newjo.put("tagName", tagName); | |
| 147 | + if (ja != null) { | |
| 148 | + ja.put(newjo); | |
| 149 | + } | |
| 150 | + } | |
| 151 | + token = null; | |
| 152 | + for (;;) { | |
| 153 | + if (token == null) { | |
| 154 | + token = x.nextToken(); | |
| 155 | + } | |
| 156 | + if (token == null) { | |
| 157 | + throw x.syntaxError("Misshaped tag"); | |
| 158 | + } | |
| 159 | + if (!(token instanceof String)) { | |
| 160 | + break; | |
| 161 | + } | |
| 162 | + | |
| 163 | +// attribute = value | |
| 164 | + | |
| 165 | + attribute = (String)token; | |
| 166 | + if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { | |
| 167 | + throw x.syntaxError("Reserved attribute."); | |
| 168 | + } | |
| 169 | + token = x.nextToken(); | |
| 170 | + if (token == XML.EQ) { | |
| 171 | + token = x.nextToken(); | |
| 172 | + if (!(token instanceof String)) { | |
| 173 | + throw x.syntaxError("Missing value"); | |
| 174 | + } | |
| 175 | + newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); | |
| 176 | + token = null; | |
| 177 | + } else { | |
| 178 | + newjo.accumulate(attribute, ""); | |
| 179 | + } | |
| 180 | + } | |
| 181 | + if (arrayForm && newjo.length() > 0) { | |
| 182 | + newja.put(newjo); | |
| 183 | + } | |
| 184 | + | |
| 185 | +// Empty tag <.../> | |
| 186 | + | |
| 187 | + if (token == XML.SLASH) { | |
| 188 | + if (x.nextToken() != XML.GT) { | |
| 189 | + throw x.syntaxError("Misshaped tag"); | |
| 190 | + } | |
| 191 | + if (ja == null) { | |
| 192 | + if (arrayForm) { | |
| 193 | + return newja; | |
| 194 | + } | |
| 195 | + return newjo; | |
| 196 | + } | |
| 197 | + | |
| 198 | +// Content, between <...> and </...> | |
| 199 | + | |
| 200 | + } else { | |
| 201 | + if (token != XML.GT) { | |
| 202 | + throw x.syntaxError("Misshaped tag"); | |
| 203 | + } | |
| 204 | + closeTag = (String)parse(x, arrayForm, newja, keepStrings); | |
| 205 | + if (closeTag != null) { | |
| 206 | + if (!closeTag.equals(tagName)) { | |
| 207 | + throw x.syntaxError("Mismatched '" + tagName + | |
| 208 | + "' and '" + closeTag + "'"); | |
| 209 | + } | |
| 210 | + tagName = null; | |
| 211 | + if (!arrayForm && newja.length() > 0) { | |
| 212 | + newjo.put("childNodes", newja); | |
| 213 | + } | |
| 214 | + if (ja == null) { | |
| 215 | + if (arrayForm) { | |
| 216 | + return newja; | |
| 217 | + } | |
| 218 | + return newjo; | |
| 219 | + } | |
| 220 | + } | |
| 221 | + } | |
| 222 | + } | |
| 223 | + } else { | |
| 224 | + if (ja != null) { | |
| 225 | + ja.put(token instanceof String | |
| 226 | + ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) | |
| 227 | + : token); | |
| 228 | + } | |
| 229 | + } | |
| 230 | + } | |
| 231 | + } | |
| 232 | + | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 236 | + * JSONArray using the JsonML transform. Each XML tag is represented as | |
| 237 | + * a JSONArray in which the first element is the tag name. If the tag has | |
| 238 | + * attributes, then the second element will be JSONObject containing the | |
| 239 | + * name/value pairs. If the tag contains children, then strings and | |
| 240 | + * JSONArrays will represent the child tags. | |
| 241 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 242 | + * @param string The source string. | |
| 243 | + * @return A JSONArray containing the structured data from the XML string. | |
| 244 | + * @throws JSONException Thrown on error converting to a JSONArray | |
| 245 | + */ | |
| 246 | + public static JSONArray toJSONArray(String string) throws JSONException { | |
| 247 | + return (JSONArray)parse(new XMLTokener(string), true, null, false); | |
| 248 | + } | |
| 249 | + | |
| 250 | + | |
| 251 | + /** | |
| 252 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 253 | + * JSONArray using the JsonML transform. Each XML tag is represented as | |
| 254 | + * a JSONArray in which the first element is the tag name. If the tag has | |
| 255 | + * attributes, then the second element will be JSONObject containing the | |
| 256 | + * name/value pairs. If the tag contains children, then strings and | |
| 257 | + * JSONArrays will represent the child tags. | |
| 258 | + * As opposed to toJSONArray this method does not attempt to convert | |
| 259 | + * any text node or attribute value to any type | |
| 260 | + * but just leaves it as a string. | |
| 261 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 262 | + * @param string The source string. | |
| 263 | + * @param keepStrings If true, then values will not be coerced into boolean | |
| 264 | + * or numeric values and will instead be left as strings | |
| 265 | + * @return A JSONArray containing the structured data from the XML string. | |
| 266 | + * @throws JSONException Thrown on error converting to a JSONArray | |
| 267 | + */ | |
| 268 | + public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { | |
| 269 | + return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); | |
| 270 | + } | |
| 271 | + | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 275 | + * JSONArray using the JsonML transform. Each XML tag is represented as | |
| 276 | + * a JSONArray in which the first element is the tag name. If the tag has | |
| 277 | + * attributes, then the second element will be JSONObject containing the | |
| 278 | + * name/value pairs. If the tag contains children, then strings and | |
| 279 | + * JSONArrays will represent the child content and tags. | |
| 280 | + * As opposed to toJSONArray this method does not attempt to convert | |
| 281 | + * any text node or attribute value to any type | |
| 282 | + * but just leaves it as a string. | |
| 283 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 284 | + * @param x An XMLTokener. | |
| 285 | + * @param keepStrings If true, then values will not be coerced into boolean | |
| 286 | + * or numeric values and will instead be left as strings | |
| 287 | + * @return A JSONArray containing the structured data from the XML string. | |
| 288 | + * @throws JSONException Thrown on error converting to a JSONArray | |
| 289 | + */ | |
| 290 | + public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { | |
| 291 | + return (JSONArray)parse(x, true, null, keepStrings); | |
| 292 | + } | |
| 293 | + | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 297 | + * JSONArray using the JsonML transform. Each XML tag is represented as | |
| 298 | + * a JSONArray in which the first element is the tag name. If the tag has | |
| 299 | + * attributes, then the second element will be JSONObject containing the | |
| 300 | + * name/value pairs. If the tag contains children, then strings and | |
| 301 | + * JSONArrays will represent the child content and tags. | |
| 302 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 303 | + * @param x An XMLTokener. | |
| 304 | + * @return A JSONArray containing the structured data from the XML string. | |
| 305 | + * @throws JSONException Thrown on error converting to a JSONArray | |
| 306 | + */ | |
| 307 | + public static JSONArray toJSONArray(XMLTokener x) throws JSONException { | |
| 308 | + return (JSONArray)parse(x, true, null, false); | |
| 309 | + } | |
| 310 | + | |
| 311 | + | |
| 312 | + /** | |
| 313 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 314 | + * JSONObject using the JsonML transform. Each XML tag is represented as | |
| 315 | + * a JSONObject with a "tagName" property. If the tag has attributes, then | |
| 316 | + * the attributes will be in the JSONObject as properties. If the tag | |
| 317 | + * contains children, the object will have a "childNodes" property which | |
| 318 | + * will be an array of strings and JsonML JSONObjects. | |
| 319 | + | |
| 320 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 321 | + * @param string The XML source text. | |
| 322 | + * @return A JSONObject containing the structured data from the XML string. | |
| 323 | + * @throws JSONException Thrown on error converting to a JSONObject | |
| 324 | + */ | |
| 325 | + public static JSONObject toJSONObject(String string) throws JSONException { | |
| 326 | + return (JSONObject)parse(new XMLTokener(string), false, null, false); | |
| 327 | + } | |
| 328 | + | |
| 329 | + | |
| 330 | + /** | |
| 331 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 332 | + * JSONObject using the JsonML transform. Each XML tag is represented as | |
| 333 | + * a JSONObject with a "tagName" property. If the tag has attributes, then | |
| 334 | + * the attributes will be in the JSONObject as properties. If the tag | |
| 335 | + * contains children, the object will have a "childNodes" property which | |
| 336 | + * will be an array of strings and JsonML JSONObjects. | |
| 337 | + | |
| 338 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 339 | + * @param string The XML source text. | |
| 340 | + * @param keepStrings If true, then values will not be coerced into boolean | |
| 341 | + * or numeric values and will instead be left as strings | |
| 342 | + * @return A JSONObject containing the structured data from the XML string. | |
| 343 | + * @throws JSONException Thrown on error converting to a JSONObject | |
| 344 | + */ | |
| 345 | + public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { | |
| 346 | + return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); | |
| 347 | + } | |
| 348 | + | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 352 | + * JSONObject using the JsonML transform. Each XML tag is represented as | |
| 353 | + * a JSONObject with a "tagName" property. If the tag has attributes, then | |
| 354 | + * the attributes will be in the JSONObject as properties. If the tag | |
| 355 | + * contains children, the object will have a "childNodes" property which | |
| 356 | + * will be an array of strings and JsonML JSONObjects. | |
| 357 | + | |
| 358 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 359 | + * @param x An XMLTokener of the XML source text. | |
| 360 | + * @return A JSONObject containing the structured data from the XML string. | |
| 361 | + * @throws JSONException Thrown on error converting to a JSONObject | |
| 362 | + */ | |
| 363 | + public static JSONObject toJSONObject(XMLTokener x) throws JSONException { | |
| 364 | + return (JSONObject)parse(x, false, null, false); | |
| 365 | + } | |
| 366 | + | |
| 367 | + | |
| 368 | + /** | |
| 369 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 370 | + * JSONObject using the JsonML transform. Each XML tag is represented as | |
| 371 | + * a JSONObject with a "tagName" property. If the tag has attributes, then | |
| 372 | + * the attributes will be in the JSONObject as properties. If the tag | |
| 373 | + * contains children, the object will have a "childNodes" property which | |
| 374 | + * will be an array of strings and JsonML JSONObjects. | |
| 375 | + | |
| 376 | + * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. | |
| 377 | + * @param x An XMLTokener of the XML source text. | |
| 378 | + * @param keepStrings If true, then values will not be coerced into boolean | |
| 379 | + * or numeric values and will instead be left as strings | |
| 380 | + * @return A JSONObject containing the structured data from the XML string. | |
| 381 | + * @throws JSONException Thrown on error converting to a JSONObject | |
| 382 | + */ | |
| 383 | + public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { | |
| 384 | + return (JSONObject)parse(x, false, null, keepStrings); | |
| 385 | + } | |
| 386 | + | |
| 387 | + | |
| 388 | + /** | |
| 389 | + * Reverse the JSONML transformation, making an XML text from a JSONArray. | |
| 390 | + * @param ja A JSONArray. | |
| 391 | + * @return An XML string. | |
| 392 | + * @throws JSONException Thrown on error converting to a string | |
| 393 | + */ | |
| 394 | + public static String toString(JSONArray ja) throws JSONException { | |
| 395 | + int i; | |
| 396 | + JSONObject jo; | |
| 397 | + int length; | |
| 398 | + Object object; | |
| 399 | + StringBuilder sb = new StringBuilder(); | |
| 400 | + String tagName; | |
| 401 | + | |
| 402 | +// Emit <tagName | |
| 403 | + | |
| 404 | + tagName = ja.getString(0); | |
| 405 | + XML.noSpace(tagName); | |
| 406 | + tagName = XML.escape(tagName); | |
| 407 | + sb.append('<'); | |
| 408 | + sb.append(tagName); | |
| 409 | + | |
| 410 | + object = ja.opt(1); | |
| 411 | + if (object instanceof JSONObject) { | |
| 412 | + i = 2; | |
| 413 | + jo = (JSONObject)object; | |
| 414 | + | |
| 415 | +// Emit the attributes | |
| 416 | + | |
| 417 | + // Don't use the new entrySet API to maintain Android support | |
| 418 | + for (final String key : jo.keySet()) { | |
| 419 | + final Object value = jo.opt(key); | |
| 420 | + XML.noSpace(key); | |
| 421 | + if (value != null) { | |
| 422 | + sb.append(' '); | |
| 423 | + sb.append(XML.escape(key)); | |
| 424 | + sb.append('='); | |
| 425 | + sb.append('"'); | |
| 426 | + sb.append(XML.escape(value.toString())); | |
| 427 | + sb.append('"'); | |
| 428 | + } | |
| 429 | + } | |
| 430 | + } else { | |
| 431 | + i = 1; | |
| 432 | + } | |
| 433 | + | |
| 434 | +// Emit content in body | |
| 435 | + | |
| 436 | + length = ja.length(); | |
| 437 | + if (i >= length) { | |
| 438 | + sb.append('/'); | |
| 439 | + sb.append('>'); | |
| 440 | + } else { | |
| 441 | + sb.append('>'); | |
| 442 | + do { | |
| 443 | + object = ja.get(i); | |
| 444 | + i += 1; | |
| 445 | + if (object != null) { | |
| 446 | + if (object instanceof String) { | |
| 447 | + sb.append(XML.escape(object.toString())); | |
| 448 | + } else if (object instanceof JSONObject) { | |
| 449 | + sb.append(toString((JSONObject)object)); | |
| 450 | + } else if (object instanceof JSONArray) { | |
| 451 | + sb.append(toString((JSONArray)object)); | |
| 452 | + } else { | |
| 453 | + sb.append(object.toString()); | |
| 454 | + } | |
| 455 | + } | |
| 456 | + } while (i < length); | |
| 457 | + sb.append('<'); | |
| 458 | + sb.append('/'); | |
| 459 | + sb.append(tagName); | |
| 460 | + sb.append('>'); | |
| 461 | + } | |
| 462 | + return sb.toString(); | |
| 463 | + } | |
| 464 | + | |
| 465 | + /** | |
| 466 | + * Reverse the JSONML transformation, making an XML text from a JSONObject. | |
| 467 | + * The JSONObject must contain a "tagName" property. If it has children, | |
| 468 | + * then it must have a "childNodes" property containing an array of objects. | |
| 469 | + * The other properties are attributes with string values. | |
| 470 | + * @param jo A JSONObject. | |
| 471 | + * @return An XML string. | |
| 472 | + * @throws JSONException Thrown on error converting to a string | |
| 473 | + */ | |
| 474 | + public static String toString(JSONObject jo) throws JSONException { | |
| 475 | + StringBuilder sb = new StringBuilder(); | |
| 476 | + int i; | |
| 477 | + JSONArray ja; | |
| 478 | + int length; | |
| 479 | + Object object; | |
| 480 | + String tagName; | |
| 481 | + Object value; | |
| 482 | + | |
| 483 | +//Emit <tagName | |
| 484 | + | |
| 485 | + tagName = jo.optString("tagName"); | |
| 486 | + if (tagName == null) { | |
| 487 | + return XML.escape(jo.toString()); | |
| 488 | + } | |
| 489 | + XML.noSpace(tagName); | |
| 490 | + tagName = XML.escape(tagName); | |
| 491 | + sb.append('<'); | |
| 492 | + sb.append(tagName); | |
| 493 | + | |
| 494 | +//Emit the attributes | |
| 495 | + | |
| 496 | + // Don't use the new entrySet API to maintain Android support | |
| 497 | + for (final String key : jo.keySet()) { | |
| 498 | + if (!"tagName".equals(key) && !"childNodes".equals(key)) { | |
| 499 | + XML.noSpace(key); | |
| 500 | + value = jo.opt(key); | |
| 501 | + if (value != null) { | |
| 502 | + sb.append(' '); | |
| 503 | + sb.append(XML.escape(key)); | |
| 504 | + sb.append('='); | |
| 505 | + sb.append('"'); | |
| 506 | + sb.append(XML.escape(value.toString())); | |
| 507 | + sb.append('"'); | |
| 508 | + } | |
| 509 | + } | |
| 510 | + } | |
| 511 | + | |
| 512 | +//Emit content in body | |
| 513 | + | |
| 514 | + ja = jo.optJSONArray("childNodes"); | |
| 515 | + if (ja == null) { | |
| 516 | + sb.append('/'); | |
| 517 | + sb.append('>'); | |
| 518 | + } else { | |
| 519 | + sb.append('>'); | |
| 520 | + length = ja.length(); | |
| 521 | + for (i = 0; i < length; i += 1) { | |
| 522 | + object = ja.get(i); | |
| 523 | + if (object != null) { | |
| 524 | + if (object instanceof String) { | |
| 525 | + sb.append(XML.escape(object.toString())); | |
| 526 | + } else if (object instanceof JSONObject) { | |
| 527 | + sb.append(toString((JSONObject)object)); | |
| 528 | + } else if (object instanceof JSONArray) { | |
| 529 | + sb.append(toString((JSONArray)object)); | |
| 530 | + } else { | |
| 531 | + sb.append(object.toString()); | |
| 532 | + } | |
| 533 | + } | |
| 534 | + } | |
| 535 | + sb.append('<'); | |
| 536 | + sb.append('/'); | |
| 537 | + sb.append(tagName); | |
| 538 | + sb.append('>'); | |
| 539 | + } | |
| 540 | + return sb.toString(); | |
| 541 | + } | |
| 542 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONObject.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +import java.io.Closeable; | |
| 4 | +import java.io.IOException; | |
| 5 | +import java.io.StringWriter; | |
| 6 | +import java.io.Writer; | |
| 7 | +import java.lang.reflect.Field; | |
| 8 | +import java.lang.reflect.InvocationTargetException; | |
| 9 | +import java.lang.reflect.Method; | |
| 10 | +import java.lang.reflect.Modifier; | |
| 11 | +import java.math.BigDecimal; | |
| 12 | +import java.math.BigInteger; | |
| 13 | +import java.util.*; | |
| 14 | +import java.util.Map.Entry; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * A JSONObject is an unordered collection of name/value pairs. Its external | |
| 18 | + * form is a string wrapped in curly braces with colons between the names and | |
| 19 | + * values, and commas between the values and names. The internal form is an | |
| 20 | + * object having <code>get</code> and <code>opt</code> methods for accessing | |
| 21 | + * the values by name, and <code>put</code> methods for adding or replacing | |
| 22 | + * values by name. The values can be any of these types: <code>Boolean</code>, | |
| 23 | + * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>, | |
| 24 | + * <code>String</code>, or the <code>JSONObject.NULL</code> object. A | |
| 25 | + * JSONObject constructor can be used to convert an external form JSON text | |
| 26 | + * into an internal form whose values can be retrieved with the | |
| 27 | + * <code>get</code> and <code>opt</code> methods, or to convert values into a | |
| 28 | + * JSON text using the <code>put</code> and <code>toString</code> methods. A | |
| 29 | + * <code>get</code> method returns a value if one can be found, and throws an | |
| 30 | + * exception if one cannot be found. An <code>opt</code> method returns a | |
| 31 | + * default value instead of throwing an exception, and so is useful for | |
| 32 | + * obtaining optional values. | |
| 33 | + * <p> | |
| 34 | + * The generic <code>get()</code> and <code>opt()</code> methods return an | |
| 35 | + * object, which you can cast or query for type. There are also typed | |
| 36 | + * <code>get</code> and <code>opt</code> methods that do type checking and type | |
| 37 | + * coercion for you. The opt methods differ from the get methods in that they | |
| 38 | + * do not throw. Instead, they return a specified value, such as null. | |
| 39 | + * <p> | |
| 40 | + * The <code>put</code> methods add or replace values in an object. For | |
| 41 | + * example, | |
| 42 | + * | |
| 43 | + * <pre> | |
| 44 | + * myString = new JSONObject() | |
| 45 | + * .put("JSON", "Hello, World!").toString(); | |
| 46 | + * </pre> | |
| 47 | + * | |
| 48 | + * produces the string <code>{"JSON": "Hello, World"}</code>. | |
| 49 | + * <p> | |
| 50 | + * The texts produced by the <code>toString</code> methods strictly conform to | |
| 51 | + * the JSON syntax rules. The constructors are more forgiving in the texts they | |
| 52 | + * will accept: | |
| 53 | + * <ul> | |
| 54 | + * <li>An extra <code>,</code> <small>(comma)</small> may appear just | |
| 55 | + * before the closing brace.</li> | |
| 56 | + * <li>Strings may be quoted with <code>'</code> <small>(single | |
| 57 | + * quote)</small>.</li> | |
| 58 | + * <li>Strings do not need to be quoted at all if they do not begin with a | |
| 59 | + * quote or single quote, and if they do not contain leading or trailing | |
| 60 | + * spaces, and if they do not contain any of these characters: | |
| 61 | + * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and | |
| 62 | + * if they are not the reserved words <code>true</code>, <code>false</code>, | |
| 63 | + * or <code>null</code>.</li> | |
| 64 | + * </ul> | |
| 65 | + * | |
| 66 | + * @author JSON.org | |
| 67 | + * @version 2016-08-15 | |
| 68 | + */ | |
| 69 | +public class JSONObject { | |
| 70 | + /** | |
| 71 | + * JSONObject.NULL is equivalent to the value that JavaScript calls null, | |
| 72 | + * whilst Java's null is equivalent to the value that JavaScript calls | |
| 73 | + * undefined. | |
| 74 | + */ | |
| 75 | + private static final class Null { | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * There is only intended to be a single instance of the NULL object, | |
| 79 | + * so the clone method returns itself. | |
| 80 | + * | |
| 81 | + * @return NULL. | |
| 82 | + */ | |
| 83 | + @Override | |
| 84 | + protected final Object clone() { | |
| 85 | + return this; | |
| 86 | + } | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * A Null object is equal to the null value and to itself. | |
| 90 | + * | |
| 91 | + * @param object | |
| 92 | + * An object to test for nullness. | |
| 93 | + * @return true if the object parameter is the JSONObject.NULL object or | |
| 94 | + * null. | |
| 95 | + */ | |
| 96 | + @Override | |
| 97 | + public boolean equals(Object object) { | |
| 98 | + return object == null || object == this; | |
| 99 | + } | |
| 100 | + /** | |
| 101 | + * A Null object is equal to the null value and to itself. | |
| 102 | + * | |
| 103 | + * @return always returns 0. | |
| 104 | + */ | |
| 105 | + @Override | |
| 106 | + public int hashCode() { | |
| 107 | + return 0; | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Get the "null" string value. | |
| 112 | + * | |
| 113 | + * @return The string "null". | |
| 114 | + */ | |
| 115 | + @Override | |
| 116 | + public String toString() { | |
| 117 | + return "null"; | |
| 118 | + } | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * The map where the JSONObject's properties are kept. | |
| 123 | + */ | |
| 124 | + private final Map<String, Object> map; | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * It is sometimes more convenient and less ambiguous to have a | |
| 128 | + * <code>NULL</code> object than to use Java's <code>null</code> value. | |
| 129 | + * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>. | |
| 130 | + * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>. | |
| 131 | + */ | |
| 132 | + public static final Object NULL = new Null(); | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * Construct an empty JSONObject. | |
| 136 | + */ | |
| 137 | + public JSONObject() { | |
| 138 | + // HashMap is used on purpose to ensure that elements are unordered by | |
| 139 | + // the specification. | |
| 140 | + // JSON tends to be a portable transfer format to allows the container | |
| 141 | + // implementations to rearrange their items for a faster element | |
| 142 | + // retrieval based on associative access. | |
| 143 | + // Therefore, an implementation mustn't rely on the order of the item. | |
| 144 | + this.map = new HashMap<String, Object>(); | |
| 145 | + } | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * Construct a JSONObject from a subset of another JSONObject. An array of | |
| 149 | + * strings is used to identify the keys that should be copied. Missing keys | |
| 150 | + * are ignored. | |
| 151 | + * | |
| 152 | + * @param jo | |
| 153 | + * A JSONObject. | |
| 154 | + * @param names | |
| 155 | + * An array of strings. | |
| 156 | + */ | |
| 157 | + public JSONObject(JSONObject jo, String[] names) { | |
| 158 | + this(names.length); | |
| 159 | + for (int i = 0; i < names.length; i += 1) { | |
| 160 | + try { | |
| 161 | + this.putOnce(names[i], jo.opt(names[i])); | |
| 162 | + } catch (Exception ignore) { | |
| 163 | + } | |
| 164 | + } | |
| 165 | + } | |
| 166 | + | |
| 167 | + /** | |
| 168 | + * Construct a JSONObject from a JSONTokener. | |
| 169 | + * | |
| 170 | + * @param x | |
| 171 | + * A JSONTokener object containing the source string. | |
| 172 | + * @throws JSONException | |
| 173 | + * If there is a syntax error in the source string or a | |
| 174 | + * duplicated key. | |
| 175 | + */ | |
| 176 | + public JSONObject(JSONTokener x) throws JSONException { | |
| 177 | + this(); | |
| 178 | + char c; | |
| 179 | + String key; | |
| 180 | + | |
| 181 | + if (x.nextClean() != '{') { | |
| 182 | + throw x.syntaxError("A JSONObject text must begin with '{'"); | |
| 183 | + } | |
| 184 | + for (;;) { | |
| 185 | + c = x.nextClean(); | |
| 186 | + switch (c) { | |
| 187 | + case 0: | |
| 188 | + throw x.syntaxError("A JSONObject text must end with '}'"); | |
| 189 | + case '}': | |
| 190 | + return; | |
| 191 | + default: | |
| 192 | + x.back(); | |
| 193 | + key = x.nextValue().toString(); | |
| 194 | + } | |
| 195 | + | |
| 196 | + // The key is followed by ':'. | |
| 197 | + | |
| 198 | + c = x.nextClean(); | |
| 199 | + if (c != ':') { | |
| 200 | + throw x.syntaxError("Expected a ':' after a key"); | |
| 201 | + } | |
| 202 | + | |
| 203 | + // Use syntaxError(..) to include error location | |
| 204 | + | |
| 205 | + if (key != null) { | |
| 206 | + // Check if key exists | |
| 207 | + if (this.opt(key) != null) { | |
| 208 | + // key already exists | |
| 209 | + throw x.syntaxError("Duplicate key \"" + key + "\""); | |
| 210 | + } | |
| 211 | + // Only add value if non-null | |
| 212 | + Object value = x.nextValue(); | |
| 213 | + if (value!=null) { | |
| 214 | + this.put(key, value); | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + // Pairs are separated by ','. | |
| 219 | + | |
| 220 | + switch (x.nextClean()) { | |
| 221 | + case ';': | |
| 222 | + case ',': | |
| 223 | + if (x.nextClean() == '}') { | |
| 224 | + return; | |
| 225 | + } | |
| 226 | + x.back(); | |
| 227 | + break; | |
| 228 | + case '}': | |
| 229 | + return; | |
| 230 | + default: | |
| 231 | + throw x.syntaxError("Expected a ',' or '}'"); | |
| 232 | + } | |
| 233 | + } | |
| 234 | + } | |
| 235 | + | |
| 236 | + /** | |
| 237 | + * Construct a JSONObject from a Map. | |
| 238 | + * | |
| 239 | + * @param m | |
| 240 | + * A map object that can be used to initialize the contents of | |
| 241 | + * the JSONObject. | |
| 242 | + */ | |
| 243 | + public JSONObject(Map<?, ?> m) { | |
| 244 | + if (m == null) { | |
| 245 | + this.map = new HashMap<String, Object>(); | |
| 246 | + } else { | |
| 247 | + this.map = new HashMap<String, Object>(m.size()); | |
| 248 | + for (final Entry<?, ?> e : m.entrySet()) { | |
| 249 | + final Object value = e.getValue(); | |
| 250 | + if (value != null) { | |
| 251 | + this.map.put(String.valueOf(e.getKey()), wrap(value)); | |
| 252 | + } | |
| 253 | + } | |
| 254 | + } | |
| 255 | + } | |
| 256 | + | |
| 257 | + /** | |
| 258 | + * Construct a JSONObject from an Object using bean getters. It reflects on | |
| 259 | + * all of the public methods of the object. For each of the methods with no | |
| 260 | + * parameters and a name starting with <code>"get"</code> or | |
| 261 | + * <code>"is"</code> followed by an uppercase letter, the method is invoked, | |
| 262 | + * and a key and the value returned from the getter method are put into the | |
| 263 | + * new JSONObject. | |
| 264 | + * <p> | |
| 265 | + * The key is formed by removing the <code>"get"</code> or <code>"is"</code> | |
| 266 | + * prefix. If the second remaining character is not upper case, then the | |
| 267 | + * first character is converted to lower case. | |
| 268 | + * <p> | |
| 269 | + * For example, if an object has a method named <code>"getName"</code>, and | |
| 270 | + * if the result of calling <code>object.getName()</code> is | |
| 271 | + * <code>"Larry Fine"</code>, then the JSONObject will contain | |
| 272 | + * <code>"name": "Larry Fine"</code>. | |
| 273 | + * <p> | |
| 274 | + * Methods that return <code>void</code> as well as <code>static</code> | |
| 275 | + * methods are ignored. | |
| 276 | + * | |
| 277 | + * @param bean | |
| 278 | + * An object that has getter methods that should be used to make | |
| 279 | + * a JSONObject. | |
| 280 | + */ | |
| 281 | + public JSONObject(Object bean) { | |
| 282 | + this(); | |
| 283 | + this.populateMap(bean); | |
| 284 | + } | |
| 285 | + | |
| 286 | + /** | |
| 287 | + * Construct a JSONObject from an Object, using reflection to find the | |
| 288 | + * public members. The resulting JSONObject's keys will be the strings from | |
| 289 | + * the names array, and the values will be the field values associated with | |
| 290 | + * those keys in the object. If a key is not found or not visible, then it | |
| 291 | + * will not be copied into the new JSONObject. | |
| 292 | + * | |
| 293 | + * @param object | |
| 294 | + * An object that has fields that should be used to make a | |
| 295 | + * JSONObject. | |
| 296 | + * @param names | |
| 297 | + * An array of strings, the names of the fields to be obtained | |
| 298 | + * from the object. | |
| 299 | + */ | |
| 300 | + public JSONObject(Object object, String names[]) { | |
| 301 | + this(names.length); | |
| 302 | + Class<?> c = object.getClass(); | |
| 303 | + for (int i = 0; i < names.length; i += 1) { | |
| 304 | + String name = names[i]; | |
| 305 | + try { | |
| 306 | + this.putOpt(name, c.getField(name).get(object)); | |
| 307 | + } catch (Exception ignore) { | |
| 308 | + } | |
| 309 | + } | |
| 310 | + } | |
| 311 | + | |
| 312 | + /** | |
| 313 | + * Construct a JSONObject from a source JSON text string. This is the most | |
| 314 | + * commonly used JSONObject constructor. | |
| 315 | + * | |
| 316 | + * @param source | |
| 317 | + * A string beginning with <code>{</code> <small>(left | |
| 318 | + * brace)</small> and ending with <code>}</code> | |
| 319 | + * <small>(right brace)</small>. | |
| 320 | + * @exception JSONException | |
| 321 | + * If there is a syntax error in the source string or a | |
| 322 | + * duplicated key. | |
| 323 | + */ | |
| 324 | + public JSONObject(String source) throws JSONException { | |
| 325 | + this(new JSONTokener(source)); | |
| 326 | + } | |
| 327 | + | |
| 328 | + /** | |
| 329 | + * Construct a JSONObject from a ResourceBundle. | |
| 330 | + * | |
| 331 | + * @param baseName | |
| 332 | + * The ResourceBundle base name. | |
| 333 | + * @param locale | |
| 334 | + * The Locale to load the ResourceBundle for. | |
| 335 | + * @throws JSONException | |
| 336 | + * If any JSONExceptions are detected. | |
| 337 | + */ | |
| 338 | + public JSONObject(String baseName, Locale locale) throws JSONException { | |
| 339 | + this(); | |
| 340 | + ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, | |
| 341 | + Thread.currentThread().getContextClassLoader()); | |
| 342 | + | |
| 343 | +// Iterate through the keys in the bundle. | |
| 344 | + | |
| 345 | + Enumeration<String> keys = bundle.getKeys(); | |
| 346 | + while (keys.hasMoreElements()) { | |
| 347 | + Object key = keys.nextElement(); | |
| 348 | + if (key != null) { | |
| 349 | + | |
| 350 | +// Go through the path, ensuring that there is a nested JSONObject for each | |
| 351 | +// segment except the last. Add the value using the last segment's name into | |
| 352 | +// the deepest nested JSONObject. | |
| 353 | + | |
| 354 | + String[] path = ((String) key).split("\\."); | |
| 355 | + int last = path.length - 1; | |
| 356 | + JSONObject target = this; | |
| 357 | + for (int i = 0; i < last; i += 1) { | |
| 358 | + String segment = path[i]; | |
| 359 | + JSONObject nextTarget = target.optJSONObject(segment); | |
| 360 | + if (nextTarget == null) { | |
| 361 | + nextTarget = new JSONObject(); | |
| 362 | + target.put(segment, nextTarget); | |
| 363 | + } | |
| 364 | + target = nextTarget; | |
| 365 | + } | |
| 366 | + target.put(path[last], bundle.getString((String) key)); | |
| 367 | + } | |
| 368 | + } | |
| 369 | + } | |
| 370 | + | |
| 371 | + /** | |
| 372 | + * Constructor to specify an initial capacity of the internal map. Useful for library | |
| 373 | + * internal calls where we know, or at least can best guess, how big this JSONObject | |
| 374 | + * will be. | |
| 375 | + * | |
| 376 | + * @param initialCapacity initial capacity of the internal map. | |
| 377 | + */ | |
| 378 | + protected JSONObject(int initialCapacity){ | |
| 379 | + this.map = new HashMap<String, Object>(initialCapacity); | |
| 380 | + } | |
| 381 | + | |
| 382 | + /** | |
| 383 | + * Accumulate values under a key. It is similar to the put method except | |
| 384 | + * that if there is already an object stored under the key then a JSONArray | |
| 385 | + * is stored under the key to hold all of the accumulated values. If there | |
| 386 | + * is already a JSONArray, then the new value is appended to it. In | |
| 387 | + * contrast, the put method replaces the previous value. | |
| 388 | + * | |
| 389 | + * If only one value is accumulated that is not a JSONArray, then the result | |
| 390 | + * will be the same as using put. But if multiple values are accumulated, | |
| 391 | + * then the result will be like append. | |
| 392 | + * | |
| 393 | + * @param key | |
| 394 | + * A key string. | |
| 395 | + * @param value | |
| 396 | + * An object to be accumulated under the key. | |
| 397 | + * @return this. | |
| 398 | + * @throws JSONException | |
| 399 | + * If the value is an invalid number or if the key is null. | |
| 400 | + */ | |
| 401 | + public JSONObject accumulate(String key, Object value) throws JSONException { | |
| 402 | + testValidity(value); | |
| 403 | + Object object = this.opt(key); | |
| 404 | + if (object == null) { | |
| 405 | + this.put(key, | |
| 406 | + value instanceof JSONArray ? new JSONArray().put(value) | |
| 407 | + : value); | |
| 408 | + } else if (object instanceof JSONArray) { | |
| 409 | + ((JSONArray) object).put(value); | |
| 410 | + } else { | |
| 411 | + this.put(key, new JSONArray().put(object).put(value)); | |
| 412 | + } | |
| 413 | + return this; | |
| 414 | + } | |
| 415 | + | |
| 416 | + /** | |
| 417 | + * Append values to the array under a key. If the key does not exist in the | |
| 418 | + * JSONObject, then the key is put in the JSONObject with its value being a | |
| 419 | + * JSONArray containing the value parameter. If the key was already | |
| 420 | + * associated with a JSONArray, then the value parameter is appended to it. | |
| 421 | + * | |
| 422 | + * @param key | |
| 423 | + * A key string. | |
| 424 | + * @param value | |
| 425 | + * An object to be accumulated under the key. | |
| 426 | + * @return this. | |
| 427 | + * @throws JSONException | |
| 428 | + * If the key is null or if the current value associated with | |
| 429 | + * the key is not a JSONArray. | |
| 430 | + */ | |
| 431 | + public JSONObject append(String key, Object value) throws JSONException { | |
| 432 | + testValidity(value); | |
| 433 | + Object object = this.opt(key); | |
| 434 | + if (object == null) { | |
| 435 | + this.put(key, new JSONArray().put(value)); | |
| 436 | + } else if (object instanceof JSONArray) { | |
| 437 | + this.put(key, ((JSONArray) object).put(value)); | |
| 438 | + } else { | |
| 439 | + throw new JSONException("JSONObject[" + key | |
| 440 | + + "] is not a JSONArray."); | |
| 441 | + } | |
| 442 | + return this; | |
| 443 | + } | |
| 444 | + | |
| 445 | + /** | |
| 446 | + * Produce a string from a double. The string "null" will be returned if the | |
| 447 | + * number is not finite. | |
| 448 | + * | |
| 449 | + * @param d | |
| 450 | + * A double. | |
| 451 | + * @return A String. | |
| 452 | + */ | |
| 453 | + public static String doubleToString(double d) { | |
| 454 | + if (Double.isInfinite(d) || Double.isNaN(d)) { | |
| 455 | + return "null"; | |
| 456 | + } | |
| 457 | + | |
| 458 | +// Shave off trailing zeros and decimal point, if possible. | |
| 459 | + | |
| 460 | + String string = Double.toString(d); | |
| 461 | + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 | |
| 462 | + && string.indexOf('E') < 0) { | |
| 463 | + while (string.endsWith("0")) { | |
| 464 | + string = string.substring(0, string.length() - 1); | |
| 465 | + } | |
| 466 | + if (string.endsWith(".")) { | |
| 467 | + string = string.substring(0, string.length() - 1); | |
| 468 | + } | |
| 469 | + } | |
| 470 | + return string; | |
| 471 | + } | |
| 472 | + | |
| 473 | + /** | |
| 474 | + * Get the value object associated with a key. | |
| 475 | + * | |
| 476 | + * @param key | |
| 477 | + * A key string. | |
| 478 | + * @return The object associated with the key. | |
| 479 | + * @throws JSONException | |
| 480 | + * if the key is not found. | |
| 481 | + */ | |
| 482 | + public Object get(String key) throws JSONException { | |
| 483 | + if (key == null) { | |
| 484 | + throw new JSONException("Null key."); | |
| 485 | + } | |
| 486 | + Object object = this.opt(key); | |
| 487 | + if (object == null) { | |
| 488 | + throw new JSONException("JSONObject[" + quote(key) + "] not found."); | |
| 489 | + } | |
| 490 | + return object; | |
| 491 | + } | |
| 492 | + | |
| 493 | + /** | |
| 494 | + * Get the enum value associated with a key. | |
| 495 | + * | |
| 496 | + * @param clazz | |
| 497 | + * The type of enum to retrieve. | |
| 498 | + * @param key | |
| 499 | + * A key string. | |
| 500 | + * @return The enum value associated with the key | |
| 501 | + * @throws JSONException | |
| 502 | + * if the key is not found or if the value cannot be converted | |
| 503 | + * to an enum. | |
| 504 | + */ | |
| 505 | + public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) throws JSONException { | |
| 506 | + E val = optEnum(clazz, key); | |
| 507 | + if(val==null) { | |
| 508 | + // JSONException should really take a throwable argument. | |
| 509 | + // If it did, I would re-implement this with the Enum.valueOf | |
| 510 | + // method and place any thrown exception in the JSONException | |
| 511 | + throw new JSONException("JSONObject[" + quote(key) | |
| 512 | + + "] is not an enum of type " + quote(clazz.getSimpleName()) | |
| 513 | + + "."); | |
| 514 | + } | |
| 515 | + return val; | |
| 516 | + } | |
| 517 | + | |
| 518 | + /** | |
| 519 | + * Get the boolean value associated with a key. | |
| 520 | + * | |
| 521 | + * @param key | |
| 522 | + * A key string. | |
| 523 | + * @return The truth. | |
| 524 | + * @throws JSONException | |
| 525 | + * if the value is not a Boolean or the String "true" or | |
| 526 | + * "false". | |
| 527 | + */ | |
| 528 | + public boolean getBoolean(String key) throws JSONException { | |
| 529 | + Object object = this.get(key); | |
| 530 | + if (object.equals(Boolean.FALSE) | |
| 531 | + || (object instanceof String && ((String) object) | |
| 532 | + .equalsIgnoreCase("false"))) { | |
| 533 | + return false; | |
| 534 | + } else if (object.equals(Boolean.TRUE) | |
| 535 | + || (object instanceof String && ((String) object) | |
| 536 | + .equalsIgnoreCase("true"))) { | |
| 537 | + return true; | |
| 538 | + } | |
| 539 | + throw new JSONException("JSONObject[" + quote(key) | |
| 540 | + + "] is not a Boolean."); | |
| 541 | + } | |
| 542 | + | |
| 543 | + /** | |
| 544 | + * Get the BigInteger value associated with a key. | |
| 545 | + * | |
| 546 | + * @param key | |
| 547 | + * A key string. | |
| 548 | + * @return The numeric value. | |
| 549 | + * @throws JSONException | |
| 550 | + * if the key is not found or if the value cannot | |
| 551 | + * be converted to BigInteger. | |
| 552 | + */ | |
| 553 | + public BigInteger getBigInteger(String key) throws JSONException { | |
| 554 | + Object object = this.get(key); | |
| 555 | + try { | |
| 556 | + return new BigInteger(object.toString()); | |
| 557 | + } catch (Exception e) { | |
| 558 | + throw new JSONException("JSONObject[" + quote(key) | |
| 559 | + + "] could not be converted to BigInteger.", e); | |
| 560 | + } | |
| 561 | + } | |
| 562 | + | |
| 563 | + /** | |
| 564 | + * Get the BigDecimal value associated with a key. | |
| 565 | + * | |
| 566 | + * @param key | |
| 567 | + * A key string. | |
| 568 | + * @return The numeric value. | |
| 569 | + * @throws JSONException | |
| 570 | + * if the key is not found or if the value | |
| 571 | + * cannot be converted to BigDecimal. | |
| 572 | + */ | |
| 573 | + public BigDecimal getBigDecimal(String key) throws JSONException { | |
| 574 | + Object object = this.get(key); | |
| 575 | + if (object instanceof BigDecimal) { | |
| 576 | + return (BigDecimal)object; | |
| 577 | + } | |
| 578 | + try { | |
| 579 | + return new BigDecimal(object.toString()); | |
| 580 | + } catch (Exception e) { | |
| 581 | + throw new JSONException("JSONObject[" + quote(key) | |
| 582 | + + "] could not be converted to BigDecimal.", e); | |
| 583 | + } | |
| 584 | + } | |
| 585 | + | |
| 586 | + /** | |
| 587 | + * Get the double value associated with a key. | |
| 588 | + * | |
| 589 | + * @param key | |
| 590 | + * A key string. | |
| 591 | + * @return The numeric value. | |
| 592 | + * @throws JSONException | |
| 593 | + * if the key is not found or if the value is not a Number | |
| 594 | + * object and cannot be converted to a number. | |
| 595 | + */ | |
| 596 | + public double getDouble(String key) throws JSONException { | |
| 597 | + Object object = this.get(key); | |
| 598 | + try { | |
| 599 | + return object instanceof Number ? ((Number) object).doubleValue() | |
| 600 | + : Double.parseDouble(object.toString()); | |
| 601 | + } catch (Exception e) { | |
| 602 | + throw new JSONException("JSONObject[" + quote(key) | |
| 603 | + + "] is not a number.", e); | |
| 604 | + } | |
| 605 | + } | |
| 606 | + | |
| 607 | + /** | |
| 608 | + * Get the float value associated with a key. | |
| 609 | + * | |
| 610 | + * @param key | |
| 611 | + * A key string. | |
| 612 | + * @return The numeric value. | |
| 613 | + * @throws JSONException | |
| 614 | + * if the key is not found or if the value is not a Number | |
| 615 | + * object and cannot be converted to a number. | |
| 616 | + */ | |
| 617 | + public float getFloat(String key) throws JSONException { | |
| 618 | + Object object = this.get(key); | |
| 619 | + try { | |
| 620 | + return object instanceof Number ? ((Number) object).floatValue() | |
| 621 | + : Float.parseFloat(object.toString()); | |
| 622 | + } catch (Exception e) { | |
| 623 | + throw new JSONException("JSONObject[" + quote(key) | |
| 624 | + + "] is not a number.", e); | |
| 625 | + } | |
| 626 | + } | |
| 627 | + | |
| 628 | + /** | |
| 629 | + * Get the Number value associated with a key. | |
| 630 | + * | |
| 631 | + * @param key | |
| 632 | + * A key string. | |
| 633 | + * @return The numeric value. | |
| 634 | + * @throws JSONException | |
| 635 | + * if the key is not found or if the value is not a Number | |
| 636 | + * object and cannot be converted to a number. | |
| 637 | + */ | |
| 638 | + public Number getNumber(String key) throws JSONException { | |
| 639 | + Object object = this.get(key); | |
| 640 | + try { | |
| 641 | + if (object instanceof Number) { | |
| 642 | + return (Number)object; | |
| 643 | + } | |
| 644 | + return stringToNumber(object.toString()); | |
| 645 | + } catch (Exception e) { | |
| 646 | + throw new JSONException("JSONObject[" + quote(key) | |
| 647 | + + "] is not a number.", e); | |
| 648 | + } | |
| 649 | + } | |
| 650 | + | |
| 651 | + /** | |
| 652 | + * Get the int value associated with a key. | |
| 653 | + * | |
| 654 | + * @param key | |
| 655 | + * A key string. | |
| 656 | + * @return The integer value. | |
| 657 | + * @throws JSONException | |
| 658 | + * if the key is not found or if the value cannot be converted | |
| 659 | + * to an integer. | |
| 660 | + */ | |
| 661 | + public int getInt(String key) throws JSONException { | |
| 662 | + Object object = this.get(key); | |
| 663 | + try { | |
| 664 | + return object instanceof Number ? ((Number) object).intValue() | |
| 665 | + : Integer.parseInt((String) object); | |
| 666 | + } catch (Exception e) { | |
| 667 | + throw new JSONException("JSONObject[" + quote(key) | |
| 668 | + + "] is not an int.", e); | |
| 669 | + } | |
| 670 | + } | |
| 671 | + | |
| 672 | + /** | |
| 673 | + * Get the JSONArray value associated with a key. | |
| 674 | + * | |
| 675 | + * @param key | |
| 676 | + * A key string. | |
| 677 | + * @return A JSONArray which is the value. | |
| 678 | + * @throws JSONException | |
| 679 | + * if the key is not found or if the value is not a JSONArray. | |
| 680 | + */ | |
| 681 | + public JSONArray getJSONArray(String key) throws JSONException { | |
| 682 | + Object object = this.get(key); | |
| 683 | + if (object instanceof JSONArray) { | |
| 684 | + return (JSONArray) object; | |
| 685 | + } | |
| 686 | + throw new JSONException("JSONObject[" + quote(key) | |
| 687 | + + "] is not a JSONArray."); | |
| 688 | + } | |
| 689 | + | |
| 690 | + /** | |
| 691 | + * Get the JSONObject value associated with a key. | |
| 692 | + * | |
| 693 | + * @param key | |
| 694 | + * A key string. | |
| 695 | + * @return A JSONObject which is the value. | |
| 696 | + * @throws JSONException | |
| 697 | + * if the key is not found or if the value is not a JSONObject. | |
| 698 | + */ | |
| 699 | + public JSONObject getJSONObject(String key) throws JSONException { | |
| 700 | + Object object = this.get(key); | |
| 701 | + if (object instanceof JSONObject) { | |
| 702 | + return (JSONObject) object; | |
| 703 | + } | |
| 704 | + throw new JSONException("JSONObject[" + quote(key) | |
| 705 | + + "] is not a JSONObject."); | |
| 706 | + } | |
| 707 | + | |
| 708 | + /** | |
| 709 | + * Get the long value associated with a key. | |
| 710 | + * | |
| 711 | + * @param key | |
| 712 | + * A key string. | |
| 713 | + * @return The long value. | |
| 714 | + * @throws JSONException | |
| 715 | + * if the key is not found or if the value cannot be converted | |
| 716 | + * to a long. | |
| 717 | + */ | |
| 718 | + public long getLong(String key) throws JSONException { | |
| 719 | + Object object = this.get(key); | |
| 720 | + try { | |
| 721 | + return object instanceof Number ? ((Number) object).longValue() | |
| 722 | + : Long.parseLong((String) object); | |
| 723 | + } catch (Exception e) { | |
| 724 | + throw new JSONException("JSONObject[" + quote(key) | |
| 725 | + + "] is not a long.", e); | |
| 726 | + } | |
| 727 | + } | |
| 728 | + | |
| 729 | + /** | |
| 730 | + * Get an array of field names from a JSONObject. | |
| 731 | + * | |
| 732 | + * @return An array of field names, or null if there are no names. | |
| 733 | + */ | |
| 734 | + public static String[] getNames(JSONObject jo) { | |
| 735 | + int length = jo.length(); | |
| 736 | + if (length == 0) { | |
| 737 | + return null; | |
| 738 | + } | |
| 739 | + return jo.keySet().toArray(new String[length]); | |
| 740 | + } | |
| 741 | + | |
| 742 | + /** | |
| 743 | + * Get an array of field names from an Object. | |
| 744 | + * | |
| 745 | + * @return An array of field names, or null if there are no names. | |
| 746 | + */ | |
| 747 | + public static String[] getNames(Object object) { | |
| 748 | + if (object == null) { | |
| 749 | + return null; | |
| 750 | + } | |
| 751 | + Class<?> klass = object.getClass(); | |
| 752 | + Field[] fields = klass.getFields(); | |
| 753 | + int length = fields.length; | |
| 754 | + if (length == 0) { | |
| 755 | + return null; | |
| 756 | + } | |
| 757 | + String[] names = new String[length]; | |
| 758 | + for (int i = 0; i < length; i += 1) { | |
| 759 | + names[i] = fields[i].getName(); | |
| 760 | + } | |
| 761 | + return names; | |
| 762 | + } | |
| 763 | + | |
| 764 | + /** | |
| 765 | + * Get the string associated with a key. | |
| 766 | + * | |
| 767 | + * @param key | |
| 768 | + * A key string. | |
| 769 | + * @return A string which is the value. | |
| 770 | + * @throws JSONException | |
| 771 | + * if there is no string value for the key. | |
| 772 | + */ | |
| 773 | + public String getString(String key) throws JSONException { | |
| 774 | + Object object = this.get(key); | |
| 775 | + if (object instanceof String) { | |
| 776 | + return (String) object; | |
| 777 | + } | |
| 778 | + throw new JSONException("JSONObject[" + quote(key) + "] not a string."); | |
| 779 | + } | |
| 780 | + | |
| 781 | + /** | |
| 782 | + * Determine if the JSONObject contains a specific key. | |
| 783 | + * | |
| 784 | + * @param key | |
| 785 | + * A key string. | |
| 786 | + * @return true if the key exists in the JSONObject. | |
| 787 | + */ | |
| 788 | + public boolean has(String key) { | |
| 789 | + return this.map.containsKey(key); | |
| 790 | + } | |
| 791 | + | |
| 792 | + /** | |
| 793 | + * Increment a property of a JSONObject. If there is no such property, | |
| 794 | + * create one with a value of 1. If there is such a property, and if it is | |
| 795 | + * an Integer, Long, Double, or Float, then add one to it. | |
| 796 | + * | |
| 797 | + * @param key | |
| 798 | + * A key string. | |
| 799 | + * @return this. | |
| 800 | + * @throws JSONException | |
| 801 | + * If there is already a property with this name that is not an | |
| 802 | + * Integer, Long, Double, or Float. | |
| 803 | + */ | |
| 804 | + public JSONObject increment(String key) throws JSONException { | |
| 805 | + Object value = this.opt(key); | |
| 806 | + if (value == null) { | |
| 807 | + this.put(key, 1); | |
| 808 | + } else if (value instanceof BigInteger) { | |
| 809 | + this.put(key, ((BigInteger)value).add(BigInteger.ONE)); | |
| 810 | + } else if (value instanceof BigDecimal) { | |
| 811 | + this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); | |
| 812 | + } else if (value instanceof Integer) { | |
| 813 | + this.put(key, ((Integer) value).intValue() + 1); | |
| 814 | + } else if (value instanceof Long) { | |
| 815 | + this.put(key, ((Long) value).longValue() + 1L); | |
| 816 | + } else if (value instanceof Double) { | |
| 817 | + this.put(key, ((Double) value).doubleValue() + 1.0d); | |
| 818 | + } else if (value instanceof Float) { | |
| 819 | + this.put(key, ((Float) value).floatValue() + 1.0f); | |
| 820 | + } else { | |
| 821 | + throw new JSONException("Unable to increment [" + quote(key) + "]."); | |
| 822 | + } | |
| 823 | + return this; | |
| 824 | + } | |
| 825 | + | |
| 826 | + /** | |
| 827 | + * Determine if the value associated with the key is null or if there is no | |
| 828 | + * value. | |
| 829 | + * | |
| 830 | + * @param key | |
| 831 | + * A key string. | |
| 832 | + * @return true if there is no value associated with the key or if the value | |
| 833 | + * is the JSONObject.NULL object. | |
| 834 | + */ | |
| 835 | + public boolean isNull(String key) { | |
| 836 | + return JSONObject.NULL.equals(this.opt(key)); | |
| 837 | + } | |
| 838 | + | |
| 839 | + /** | |
| 840 | + * Get an enumeration of the keys of the JSONObject. Modifying this key Set will also | |
| 841 | + * modify the JSONObject. Use with caution. | |
| 842 | + * | |
| 843 | + * @see Set#iterator() | |
| 844 | + * | |
| 845 | + * @return An iterator of the keys. | |
| 846 | + */ | |
| 847 | + public Iterator<String> keys() { | |
| 848 | + return this.keySet().iterator(); | |
| 849 | + } | |
| 850 | + | |
| 851 | + /** | |
| 852 | + * Get a set of keys of the JSONObject. Modifying this key Set will also modify the | |
| 853 | + * JSONObject. Use with caution. | |
| 854 | + * | |
| 855 | + * @see Map#keySet() | |
| 856 | + * | |
| 857 | + * @return A keySet. | |
| 858 | + */ | |
| 859 | + public Set<String> keySet() { | |
| 860 | + return this.map.keySet(); | |
| 861 | + } | |
| 862 | + | |
| 863 | + /** | |
| 864 | + * Get a set of entries of the JSONObject. These are raw values and may not | |
| 865 | + * match what is returned by the JSONObject get* and opt* functions. Modifying | |
| 866 | + * the returned EntrySet or the Entry objects contained therein will modify the | |
| 867 | + * backing JSONObject. This does not return a clone or a read-only view. | |
| 868 | + * | |
| 869 | + * Use with caution. | |
| 870 | + * | |
| 871 | + * @see Map#entrySet() | |
| 872 | + * | |
| 873 | + * @return An Entry Set | |
| 874 | + */ | |
| 875 | + protected Set<Entry<String, Object>> entrySet() { | |
| 876 | + return this.map.entrySet(); | |
| 877 | + } | |
| 878 | + | |
| 879 | + /** | |
| 880 | + * Get the number of keys stored in the JSONObject. | |
| 881 | + * | |
| 882 | + * @return The number of keys in the JSONObject. | |
| 883 | + */ | |
| 884 | + public int length() { | |
| 885 | + return this.map.size(); | |
| 886 | + } | |
| 887 | + | |
| 888 | + /** | |
| 889 | + * Produce a JSONArray containing the names of the elements of this | |
| 890 | + * JSONObject. | |
| 891 | + * | |
| 892 | + * @return A JSONArray containing the key strings, or null if the JSONObject | |
| 893 | + * is empty. | |
| 894 | + */ | |
| 895 | + public JSONArray names() { | |
| 896 | + if(this.map.isEmpty()) { | |
| 897 | + return null; | |
| 898 | + } | |
| 899 | + return new JSONArray(this.map.keySet()); | |
| 900 | + } | |
| 901 | + | |
| 902 | + /** | |
| 903 | + * Produce a string from a Number. | |
| 904 | + * | |
| 905 | + * @param number | |
| 906 | + * A Number | |
| 907 | + * @return A String. | |
| 908 | + * @throws JSONException | |
| 909 | + * If n is a non-finite number. | |
| 910 | + */ | |
| 911 | + public static String numberToString(Number number) throws JSONException { | |
| 912 | + if (number == null) { | |
| 913 | + throw new JSONException("Null pointer"); | |
| 914 | + } | |
| 915 | + testValidity(number); | |
| 916 | + | |
| 917 | + // Shave off trailing zeros and decimal point, if possible. | |
| 918 | + | |
| 919 | + String string = number.toString(); | |
| 920 | + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 | |
| 921 | + && string.indexOf('E') < 0) { | |
| 922 | + while (string.endsWith("0")) { | |
| 923 | + string = string.substring(0, string.length() - 1); | |
| 924 | + } | |
| 925 | + if (string.endsWith(".")) { | |
| 926 | + string = string.substring(0, string.length() - 1); | |
| 927 | + } | |
| 928 | + } | |
| 929 | + return string; | |
| 930 | + } | |
| 931 | + | |
| 932 | + /** | |
| 933 | + * Get an optional value associated with a key. | |
| 934 | + * | |
| 935 | + * @param key | |
| 936 | + * A key string. | |
| 937 | + * @return An object which is the value, or null if there is no value. | |
| 938 | + */ | |
| 939 | + public Object opt(String key) { | |
| 940 | + return key == null ? null : this.map.get(key); | |
| 941 | + } | |
| 942 | + | |
| 943 | + /** | |
| 944 | + * Get the enum value associated with a key. | |
| 945 | + * | |
| 946 | + * @param clazz | |
| 947 | + * The type of enum to retrieve. | |
| 948 | + * @param key | |
| 949 | + * A key string. | |
| 950 | + * @return The enum value associated with the key or null if not found | |
| 951 | + */ | |
| 952 | + public <E extends Enum<E>> E optEnum(Class<E> clazz, String key) { | |
| 953 | + return this.optEnum(clazz, key, null); | |
| 954 | + } | |
| 955 | + | |
| 956 | + /** | |
| 957 | + * Get the enum value associated with a key. | |
| 958 | + * | |
| 959 | + * @param clazz | |
| 960 | + * The type of enum to retrieve. | |
| 961 | + * @param key | |
| 962 | + * A key string. | |
| 963 | + * @param defaultValue | |
| 964 | + * The default in case the value is not found | |
| 965 | + * @return The enum value associated with the key or defaultValue | |
| 966 | + * if the value is not found or cannot be assigned to <code>clazz</code> | |
| 967 | + */ | |
| 968 | + public <E extends Enum<E>> E optEnum(Class<E> clazz, String key, E defaultValue) { | |
| 969 | + try { | |
| 970 | + Object val = this.opt(key); | |
| 971 | + if (NULL.equals(val)) { | |
| 972 | + return defaultValue; | |
| 973 | + } | |
| 974 | + if (clazz.isAssignableFrom(val.getClass())) { | |
| 975 | + // we just checked it! | |
| 976 | + @SuppressWarnings("unchecked") | |
| 977 | + E myE = (E) val; | |
| 978 | + return myE; | |
| 979 | + } | |
| 980 | + return Enum.valueOf(clazz, val.toString()); | |
| 981 | + } catch (IllegalArgumentException e) { | |
| 982 | + return defaultValue; | |
| 983 | + } catch (NullPointerException e) { | |
| 984 | + return defaultValue; | |
| 985 | + } | |
| 986 | + } | |
| 987 | + | |
| 988 | + /** | |
| 989 | + * Get an optional boolean associated with a key. It returns false if there | |
| 990 | + * is no such key, or if the value is not Boolean.TRUE or the String "true". | |
| 991 | + * | |
| 992 | + * @param key | |
| 993 | + * A key string. | |
| 994 | + * @return The truth. | |
| 995 | + */ | |
| 996 | + public boolean optBoolean(String key) { | |
| 997 | + return this.optBoolean(key, false); | |
| 998 | + } | |
| 999 | + | |
| 1000 | + /** | |
| 1001 | + * Get an optional boolean associated with a key. It returns the | |
| 1002 | + * defaultValue if there is no such key, or if it is not a Boolean or the | |
| 1003 | + * String "true" or "false" (case insensitive). | |
| 1004 | + * | |
| 1005 | + * @param key | |
| 1006 | + * A key string. | |
| 1007 | + * @param defaultValue | |
| 1008 | + * The default. | |
| 1009 | + * @return The truth. | |
| 1010 | + */ | |
| 1011 | + public boolean optBoolean(String key, boolean defaultValue) { | |
| 1012 | + Object val = this.opt(key); | |
| 1013 | + if (NULL.equals(val)) { | |
| 1014 | + return defaultValue; | |
| 1015 | + } | |
| 1016 | + if (val instanceof Boolean){ | |
| 1017 | + return ((Boolean) val).booleanValue(); | |
| 1018 | + } | |
| 1019 | + try { | |
| 1020 | + // we'll use the get anyway because it does string conversion. | |
| 1021 | + return this.getBoolean(key); | |
| 1022 | + } catch (Exception e) { | |
| 1023 | + return defaultValue; | |
| 1024 | + } | |
| 1025 | + } | |
| 1026 | + | |
| 1027 | + /** | |
| 1028 | + * Get an optional BigDecimal associated with a key, or the defaultValue if | |
| 1029 | + * there is no such key or if its value is not a number. If the value is a | |
| 1030 | + * string, an attempt will be made to evaluate it as a number. | |
| 1031 | + * | |
| 1032 | + * @param key | |
| 1033 | + * A key string. | |
| 1034 | + * @param defaultValue | |
| 1035 | + * The default. | |
| 1036 | + * @return An object which is the value. | |
| 1037 | + */ | |
| 1038 | + public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { | |
| 1039 | + Object val = this.opt(key); | |
| 1040 | + if (NULL.equals(val)) { | |
| 1041 | + return defaultValue; | |
| 1042 | + } | |
| 1043 | + if (val instanceof BigDecimal){ | |
| 1044 | + return (BigDecimal) val; | |
| 1045 | + } | |
| 1046 | + if (val instanceof BigInteger){ | |
| 1047 | + return new BigDecimal((BigInteger) val); | |
| 1048 | + } | |
| 1049 | + if (val instanceof Double || val instanceof Float){ | |
| 1050 | + return new BigDecimal(((Number) val).doubleValue()); | |
| 1051 | + } | |
| 1052 | + if (val instanceof Long || val instanceof Integer | |
| 1053 | + || val instanceof Short || val instanceof Byte){ | |
| 1054 | + return new BigDecimal(((Number) val).longValue()); | |
| 1055 | + } | |
| 1056 | + // don't check if it's a string in case of unchecked Number subclasses | |
| 1057 | + try { | |
| 1058 | + return new BigDecimal(val.toString()); | |
| 1059 | + } catch (Exception e) { | |
| 1060 | + return defaultValue; | |
| 1061 | + } | |
| 1062 | + } | |
| 1063 | + | |
| 1064 | + /** | |
| 1065 | + * Get an optional BigInteger associated with a key, or the defaultValue if | |
| 1066 | + * there is no such key or if its value is not a number. If the value is a | |
| 1067 | + * string, an attempt will be made to evaluate it as a number. | |
| 1068 | + * | |
| 1069 | + * @param key | |
| 1070 | + * A key string. | |
| 1071 | + * @param defaultValue | |
| 1072 | + * The default. | |
| 1073 | + * @return An object which is the value. | |
| 1074 | + */ | |
| 1075 | + public BigInteger optBigInteger(String key, BigInteger defaultValue) { | |
| 1076 | + Object val = this.opt(key); | |
| 1077 | + if (NULL.equals(val)) { | |
| 1078 | + return defaultValue; | |
| 1079 | + } | |
| 1080 | + if (val instanceof BigInteger){ | |
| 1081 | + return (BigInteger) val; | |
| 1082 | + } | |
| 1083 | + if (val instanceof BigDecimal){ | |
| 1084 | + return ((BigDecimal) val).toBigInteger(); | |
| 1085 | + } | |
| 1086 | + if (val instanceof Double || val instanceof Float){ | |
| 1087 | + return new BigDecimal(((Number) val).doubleValue()).toBigInteger(); | |
| 1088 | + } | |
| 1089 | + if (val instanceof Long || val instanceof Integer | |
| 1090 | + || val instanceof Short || val instanceof Byte){ | |
| 1091 | + return BigInteger.valueOf(((Number) val).longValue()); | |
| 1092 | + } | |
| 1093 | + // don't check if it's a string in case of unchecked Number subclasses | |
| 1094 | + try { | |
| 1095 | + // the other opt functions handle implicit conversions, i.e. | |
| 1096 | + // jo.put("double",1.1d); | |
| 1097 | + // jo.optInt("double"); -- will return 1, not an error | |
| 1098 | + // this conversion to BigDecimal then to BigInteger is to maintain | |
| 1099 | + // that type cast support that may truncate the decimal. | |
| 1100 | + final String valStr = val.toString(); | |
| 1101 | + if(isDecimalNotation(valStr)) { | |
| 1102 | + return new BigDecimal(valStr).toBigInteger(); | |
| 1103 | + } | |
| 1104 | + return new BigInteger(valStr); | |
| 1105 | + } catch (Exception e) { | |
| 1106 | + return defaultValue; | |
| 1107 | + } | |
| 1108 | + } | |
| 1109 | + | |
| 1110 | + /** | |
| 1111 | + * Get an optional double associated with a key, or NaN if there is no such | |
| 1112 | + * key or if its value is not a number. If the value is a string, an attempt | |
| 1113 | + * will be made to evaluate it as a number. | |
| 1114 | + * | |
| 1115 | + * @param key | |
| 1116 | + * A string which is the key. | |
| 1117 | + * @return An object which is the value. | |
| 1118 | + */ | |
| 1119 | + public double optDouble(String key) { | |
| 1120 | + return this.optDouble(key, Double.NaN); | |
| 1121 | + } | |
| 1122 | + | |
| 1123 | + /** | |
| 1124 | + * Get an optional double associated with a key, or the defaultValue if | |
| 1125 | + * there is no such key or if its value is not a number. If the value is a | |
| 1126 | + * string, an attempt will be made to evaluate it as a number. | |
| 1127 | + * | |
| 1128 | + * @param key | |
| 1129 | + * A key string. | |
| 1130 | + * @param defaultValue | |
| 1131 | + * The default. | |
| 1132 | + * @return An object which is the value. | |
| 1133 | + */ | |
| 1134 | + public double optDouble(String key, double defaultValue) { | |
| 1135 | + Object val = this.opt(key); | |
| 1136 | + if (NULL.equals(val)) { | |
| 1137 | + return defaultValue; | |
| 1138 | + } | |
| 1139 | + if (val instanceof Number){ | |
| 1140 | + return ((Number) val).doubleValue(); | |
| 1141 | + } | |
| 1142 | + if (val instanceof String) { | |
| 1143 | + try { | |
| 1144 | + return Double.parseDouble((String) val); | |
| 1145 | + } catch (Exception e) { | |
| 1146 | + return defaultValue; | |
| 1147 | + } | |
| 1148 | + } | |
| 1149 | + return defaultValue; | |
| 1150 | + } | |
| 1151 | + | |
| 1152 | + /** | |
| 1153 | + * Get the optional double value associated with an index. NaN is returned | |
| 1154 | + * if there is no value for the index, or if the value is not a number and | |
| 1155 | + * cannot be converted to a number. | |
| 1156 | + * | |
| 1157 | + * @param key | |
| 1158 | + * A key string. | |
| 1159 | + * @return The value. | |
| 1160 | + */ | |
| 1161 | + public float optFloat(String key) { | |
| 1162 | + return this.optFloat(key, Float.NaN); | |
| 1163 | + } | |
| 1164 | + | |
| 1165 | + /** | |
| 1166 | + * Get the optional double value associated with an index. The defaultValue | |
| 1167 | + * is returned if there is no value for the index, or if the value is not a | |
| 1168 | + * number and cannot be converted to a number. | |
| 1169 | + * | |
| 1170 | + * @param key | |
| 1171 | + * A key string. | |
| 1172 | + * @param defaultValue | |
| 1173 | + * The default value. | |
| 1174 | + * @return The value. | |
| 1175 | + */ | |
| 1176 | + public float optFloat(String key, float defaultValue) { | |
| 1177 | + Object val = this.opt(key); | |
| 1178 | + if (JSONObject.NULL.equals(val)) { | |
| 1179 | + return defaultValue; | |
| 1180 | + } | |
| 1181 | + if (val instanceof Number){ | |
| 1182 | + return ((Number) val).floatValue(); | |
| 1183 | + } | |
| 1184 | + if (val instanceof String) { | |
| 1185 | + try { | |
| 1186 | + return Float.parseFloat((String) val); | |
| 1187 | + } catch (Exception e) { | |
| 1188 | + return defaultValue; | |
| 1189 | + } | |
| 1190 | + } | |
| 1191 | + return defaultValue; | |
| 1192 | + } | |
| 1193 | + | |
| 1194 | + /** | |
| 1195 | + * Get an optional int value associated with a key, or zero if there is no | |
| 1196 | + * such key or if the value is not a number. If the value is a string, an | |
| 1197 | + * attempt will be made to evaluate it as a number. | |
| 1198 | + * | |
| 1199 | + * @param key | |
| 1200 | + * A key string. | |
| 1201 | + * @return An object which is the value. | |
| 1202 | + */ | |
| 1203 | + public int optInt(String key) { | |
| 1204 | + return this.optInt(key, 0); | |
| 1205 | + } | |
| 1206 | + | |
| 1207 | + /** | |
| 1208 | + * Get an optional int value associated with a key, or the default if there | |
| 1209 | + * is no such key or if the value is not a number. If the value is a string, | |
| 1210 | + * an attempt will be made to evaluate it as a number. | |
| 1211 | + * | |
| 1212 | + * @param key | |
| 1213 | + * A key string. | |
| 1214 | + * @param defaultValue | |
| 1215 | + * The default. | |
| 1216 | + * @return An object which is the value. | |
| 1217 | + */ | |
| 1218 | + public int optInt(String key, int defaultValue) { | |
| 1219 | + Object val = this.opt(key); | |
| 1220 | + if (NULL.equals(val)) { | |
| 1221 | + return defaultValue; | |
| 1222 | + } | |
| 1223 | + if (val instanceof Number){ | |
| 1224 | + return ((Number) val).intValue(); | |
| 1225 | + } | |
| 1226 | + | |
| 1227 | + if (val instanceof String) { | |
| 1228 | + try { | |
| 1229 | + return new BigDecimal((String) val).intValue(); | |
| 1230 | + } catch (Exception e) { | |
| 1231 | + return defaultValue; | |
| 1232 | + } | |
| 1233 | + } | |
| 1234 | + return defaultValue; | |
| 1235 | + } | |
| 1236 | + | |
| 1237 | + /** | |
| 1238 | + * Get an optional JSONArray associated with a key. It returns null if there | |
| 1239 | + * is no such key, or if its value is not a JSONArray. | |
| 1240 | + * | |
| 1241 | + * @param key | |
| 1242 | + * A key string. | |
| 1243 | + * @return A JSONArray which is the value. | |
| 1244 | + */ | |
| 1245 | + public JSONArray optJSONArray(String key) { | |
| 1246 | + Object o = this.opt(key); | |
| 1247 | + return o instanceof JSONArray ? (JSONArray) o : null; | |
| 1248 | + } | |
| 1249 | + | |
| 1250 | + /** | |
| 1251 | + * Get an optional JSONObject associated with a key. It returns null if | |
| 1252 | + * there is no such key, or if its value is not a JSONObject. | |
| 1253 | + * | |
| 1254 | + * @param key | |
| 1255 | + * A key string. | |
| 1256 | + * @return A JSONObject which is the value. | |
| 1257 | + */ | |
| 1258 | + public JSONObject optJSONObject(String key) { | |
| 1259 | + Object object = this.opt(key); | |
| 1260 | + return object instanceof JSONObject ? (JSONObject) object : null; | |
| 1261 | + } | |
| 1262 | + | |
| 1263 | + /** | |
| 1264 | + * Get an optional long value associated with a key, or zero if there is no | |
| 1265 | + * such key or if the value is not a number. If the value is a string, an | |
| 1266 | + * attempt will be made to evaluate it as a number. | |
| 1267 | + * | |
| 1268 | + * @param key | |
| 1269 | + * A key string. | |
| 1270 | + * @return An object which is the value. | |
| 1271 | + */ | |
| 1272 | + public long optLong(String key) { | |
| 1273 | + return this.optLong(key, 0); | |
| 1274 | + } | |
| 1275 | + | |
| 1276 | + /** | |
| 1277 | + * Get an optional long value associated with a key, or the default if there | |
| 1278 | + * is no such key or if the value is not a number. If the value is a string, | |
| 1279 | + * an attempt will be made to evaluate it as a number. | |
| 1280 | + * | |
| 1281 | + * @param key | |
| 1282 | + * A key string. | |
| 1283 | + * @param defaultValue | |
| 1284 | + * The default. | |
| 1285 | + * @return An object which is the value. | |
| 1286 | + */ | |
| 1287 | + public long optLong(String key, long defaultValue) { | |
| 1288 | + Object val = this.opt(key); | |
| 1289 | + if (NULL.equals(val)) { | |
| 1290 | + return defaultValue; | |
| 1291 | + } | |
| 1292 | + if (val instanceof Number){ | |
| 1293 | + return ((Number) val).longValue(); | |
| 1294 | + } | |
| 1295 | + | |
| 1296 | + if (val instanceof String) { | |
| 1297 | + try { | |
| 1298 | + return new BigDecimal((String) val).longValue(); | |
| 1299 | + } catch (Exception e) { | |
| 1300 | + return defaultValue; | |
| 1301 | + } | |
| 1302 | + } | |
| 1303 | + return defaultValue; | |
| 1304 | + } | |
| 1305 | + | |
| 1306 | + /** | |
| 1307 | + * Get an optional {@link Number} value associated with a key, or <code>null</code> | |
| 1308 | + * if there is no such key or if the value is not a number. If the value is a string, | |
| 1309 | + * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method | |
| 1310 | + * would be used in cases where type coercion of the number value is unwanted. | |
| 1311 | + * | |
| 1312 | + * @param key | |
| 1313 | + * A key string. | |
| 1314 | + * @return An object which is the value. | |
| 1315 | + */ | |
| 1316 | + public Number optNumber(String key) { | |
| 1317 | + return this.optNumber(key, null); | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + /** | |
| 1321 | + * Get an optional {@link Number} value associated with a key, or the default if there | |
| 1322 | + * is no such key or if the value is not a number. If the value is a string, | |
| 1323 | + * an attempt will be made to evaluate it as a number. This method | |
| 1324 | + * would be used in cases where type coercion of the number value is unwanted. | |
| 1325 | + * | |
| 1326 | + * @param key | |
| 1327 | + * A key string. | |
| 1328 | + * @param defaultValue | |
| 1329 | + * The default. | |
| 1330 | + * @return An object which is the value. | |
| 1331 | + */ | |
| 1332 | + public Number optNumber(String key, Number defaultValue) { | |
| 1333 | + Object val = this.opt(key); | |
| 1334 | + if (NULL.equals(val)) { | |
| 1335 | + return defaultValue; | |
| 1336 | + } | |
| 1337 | + if (val instanceof Number){ | |
| 1338 | + return (Number) val; | |
| 1339 | + } | |
| 1340 | + | |
| 1341 | + if (val instanceof String) { | |
| 1342 | + try { | |
| 1343 | + return stringToNumber((String) val); | |
| 1344 | + } catch (Exception e) { | |
| 1345 | + return defaultValue; | |
| 1346 | + } | |
| 1347 | + } | |
| 1348 | + return defaultValue; | |
| 1349 | + } | |
| 1350 | + | |
| 1351 | + /** | |
| 1352 | + * Get an optional string associated with a key. It returns an empty string | |
| 1353 | + * if there is no such key. If the value is not a string and is not null, | |
| 1354 | + * then it is converted to a string. | |
| 1355 | + * | |
| 1356 | + * @param key | |
| 1357 | + * A key string. | |
| 1358 | + * @return A string which is the value. | |
| 1359 | + */ | |
| 1360 | + public String optString(String key) { | |
| 1361 | + return this.optString(key, ""); | |
| 1362 | + } | |
| 1363 | + | |
| 1364 | + /** | |
| 1365 | + * Get an optional string associated with a key. It returns the defaultValue | |
| 1366 | + * if there is no such key. | |
| 1367 | + * | |
| 1368 | + * @param key | |
| 1369 | + * A key string. | |
| 1370 | + * @param defaultValue | |
| 1371 | + * The default. | |
| 1372 | + * @return A string which is the value. | |
| 1373 | + */ | |
| 1374 | + public String optString(String key, String defaultValue) { | |
| 1375 | + Object object = this.opt(key); | |
| 1376 | + return NULL.equals(object) ? defaultValue : object.toString(); | |
| 1377 | + } | |
| 1378 | + | |
| 1379 | + /** | |
| 1380 | + * Populates the internal map of the JSONObject with the bean properties. | |
| 1381 | + * The bean can not be recursive. | |
| 1382 | + * | |
| 1383 | + * @see JSONObject#JSONObject(Object) | |
| 1384 | + * | |
| 1385 | + * @param bean | |
| 1386 | + * the bean | |
| 1387 | + */ | |
| 1388 | + private void populateMap(Object bean) { | |
| 1389 | + Class<?> klass = bean.getClass(); | |
| 1390 | + | |
| 1391 | +// If klass is a System class then set includeSuperClass to false. | |
| 1392 | + | |
| 1393 | + boolean includeSuperClass = klass.getClassLoader() != null; | |
| 1394 | + | |
| 1395 | + Method[] methods = includeSuperClass ? klass.getMethods() : klass | |
| 1396 | + .getDeclaredMethods(); | |
| 1397 | + for (final Method method : methods) { | |
| 1398 | + final int modifiers = method.getModifiers(); | |
| 1399 | + if (Modifier.isPublic(modifiers) | |
| 1400 | + && !Modifier.isStatic(modifiers) | |
| 1401 | + && method.getParameterTypes().length == 0 | |
| 1402 | + && !method.isBridge() | |
| 1403 | + && method.getReturnType() != Void.TYPE ) { | |
| 1404 | + final String name = method.getName(); | |
| 1405 | + String key; | |
| 1406 | + if (name.startsWith("get")) { | |
| 1407 | + if ("getClass".equals(name) || "getDeclaringClass".equals(name)) { | |
| 1408 | + continue; | |
| 1409 | + } | |
| 1410 | + key = name.substring(3); | |
| 1411 | + } else if (name.startsWith("is")) { | |
| 1412 | + key = name.substring(2); | |
| 1413 | + } else { | |
| 1414 | + continue; | |
| 1415 | + } | |
| 1416 | + if (key.length() > 0 | |
| 1417 | + && Character.isUpperCase(key.charAt(0))) { | |
| 1418 | + if (key.length() == 1) { | |
| 1419 | + key = key.toLowerCase(Locale.ROOT); | |
| 1420 | + } else if (!Character.isUpperCase(key.charAt(1))) { | |
| 1421 | + key = key.substring(0, 1).toLowerCase(Locale.ROOT) | |
| 1422 | + + key.substring(1); | |
| 1423 | + } | |
| 1424 | + | |
| 1425 | + try { | |
| 1426 | + final Object result = method.invoke(bean); | |
| 1427 | + if (result != null) { | |
| 1428 | + this.map.put(key, wrap(result)); | |
| 1429 | + // we don't use the result anywhere outside of wrap | |
| 1430 | + // if it's a resource we should be sure to close it after calling toString | |
| 1431 | + if(result instanceof Closeable) { | |
| 1432 | + try { | |
| 1433 | + ((Closeable)result).close(); | |
| 1434 | + } catch (IOException ignore) { | |
| 1435 | + } | |
| 1436 | + } | |
| 1437 | + } | |
| 1438 | + } catch (IllegalAccessException ignore) { | |
| 1439 | + } catch (IllegalArgumentException ignore) { | |
| 1440 | + } catch (InvocationTargetException ignore) { | |
| 1441 | + } | |
| 1442 | + } | |
| 1443 | + } | |
| 1444 | + } | |
| 1445 | + } | |
| 1446 | + | |
| 1447 | + /** | |
| 1448 | + * Put a key/boolean pair in the JSONObject. | |
| 1449 | + * | |
| 1450 | + * @param key | |
| 1451 | + * A key string. | |
| 1452 | + * @param value | |
| 1453 | + * A boolean which is the value. | |
| 1454 | + * @return this. | |
| 1455 | + * @throws JSONException | |
| 1456 | + * If the key is null. | |
| 1457 | + */ | |
| 1458 | + public JSONObject put(String key, boolean value) throws JSONException { | |
| 1459 | + this.put(key, value ? Boolean.TRUE : Boolean.FALSE); | |
| 1460 | + return this; | |
| 1461 | + } | |
| 1462 | + | |
| 1463 | + /** | |
| 1464 | + * Put a key/value pair in the JSONObject, where the value will be a | |
| 1465 | + * JSONArray which is produced from a Collection. | |
| 1466 | + * | |
| 1467 | + * @param key | |
| 1468 | + * A key string. | |
| 1469 | + * @param value | |
| 1470 | + * A Collection value. | |
| 1471 | + * @return this. | |
| 1472 | + * @throws JSONException | |
| 1473 | + */ | |
| 1474 | + public JSONObject put(String key, Collection<?> value) throws JSONException { | |
| 1475 | + this.put(key, new JSONArray(value)); | |
| 1476 | + return this; | |
| 1477 | + } | |
| 1478 | + | |
| 1479 | + /** | |
| 1480 | + * Put a key/double pair in the JSONObject. | |
| 1481 | + * | |
| 1482 | + * @param key | |
| 1483 | + * A key string. | |
| 1484 | + * @param value | |
| 1485 | + * A double which is the value. | |
| 1486 | + * @return this. | |
| 1487 | + * @throws JSONException | |
| 1488 | + * If the key is null or if the number is invalid. | |
| 1489 | + */ | |
| 1490 | + public JSONObject put(String key, double value) throws JSONException { | |
| 1491 | + this.put(key, Double.valueOf(value)); | |
| 1492 | + return this; | |
| 1493 | + } | |
| 1494 | + | |
| 1495 | + /** | |
| 1496 | + * Put a key/float pair in the JSONObject. | |
| 1497 | + * | |
| 1498 | + * @param key | |
| 1499 | + * A key string. | |
| 1500 | + * @param value | |
| 1501 | + * A float which is the value. | |
| 1502 | + * @return this. | |
| 1503 | + * @throws JSONException | |
| 1504 | + * If the key is null or if the number is invalid. | |
| 1505 | + */ | |
| 1506 | + public JSONObject put(String key, float value) throws JSONException { | |
| 1507 | + this.put(key, Float.valueOf(value)); | |
| 1508 | + return this; | |
| 1509 | + } | |
| 1510 | + | |
| 1511 | + /** | |
| 1512 | + * Put a key/int pair in the JSONObject. | |
| 1513 | + * | |
| 1514 | + * @param key | |
| 1515 | + * A key string. | |
| 1516 | + * @param value | |
| 1517 | + * An int which is the value. | |
| 1518 | + * @return this. | |
| 1519 | + * @throws JSONException | |
| 1520 | + * If the key is null. | |
| 1521 | + */ | |
| 1522 | + public JSONObject put(String key, int value) throws JSONException { | |
| 1523 | + this.put(key, Integer.valueOf(value)); | |
| 1524 | + return this; | |
| 1525 | + } | |
| 1526 | + | |
| 1527 | + /** | |
| 1528 | + * Put a key/long pair in the JSONObject. | |
| 1529 | + * | |
| 1530 | + * @param key | |
| 1531 | + * A key string. | |
| 1532 | + * @param value | |
| 1533 | + * A long which is the value. | |
| 1534 | + * @return this. | |
| 1535 | + * @throws JSONException | |
| 1536 | + * If the key is null. | |
| 1537 | + */ | |
| 1538 | + public JSONObject put(String key, long value) throws JSONException { | |
| 1539 | + this.put(key, Long.valueOf(value)); | |
| 1540 | + return this; | |
| 1541 | + } | |
| 1542 | + | |
| 1543 | + /** | |
| 1544 | + * Put a key/value pair in the JSONObject, where the value will be a | |
| 1545 | + * JSONObject which is produced from a Map. | |
| 1546 | + * | |
| 1547 | + * @param key | |
| 1548 | + * A key string. | |
| 1549 | + * @param value | |
| 1550 | + * A Map value. | |
| 1551 | + * @return this. | |
| 1552 | + * @throws JSONException | |
| 1553 | + */ | |
| 1554 | + public JSONObject put(String key, Map<?, ?> value) throws JSONException { | |
| 1555 | + this.put(key, new JSONObject(value)); | |
| 1556 | + return this; | |
| 1557 | + } | |
| 1558 | + | |
| 1559 | + /** | |
| 1560 | + * Put a key/value pair in the JSONObject. If the value is null, then the | |
| 1561 | + * key will be removed from the JSONObject if it is present. | |
| 1562 | + * | |
| 1563 | + * @param key | |
| 1564 | + * A key string. | |
| 1565 | + * @param value | |
| 1566 | + * An object which is the value. It should be of one of these | |
| 1567 | + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, | |
| 1568 | + * String, or the JSONObject.NULL object. | |
| 1569 | + * @return this. | |
| 1570 | + * @throws JSONException | |
| 1571 | + * If the value is non-finite number or if the key is null. | |
| 1572 | + */ | |
| 1573 | + public JSONObject put(String key, Object value) throws JSONException { | |
| 1574 | + if (key == null) { | |
| 1575 | + throw new NullPointerException("Null key."); | |
| 1576 | + } | |
| 1577 | + if (value != null) { | |
| 1578 | + testValidity(value); | |
| 1579 | + this.map.put(key, value); | |
| 1580 | + } else { | |
| 1581 | + this.remove(key); | |
| 1582 | + } | |
| 1583 | + return this; | |
| 1584 | + } | |
| 1585 | + | |
| 1586 | + /** | |
| 1587 | + * Put a key/value pair in the JSONObject, but only if the key and the value | |
| 1588 | + * are both non-null, and only if there is not already a member with that | |
| 1589 | + * name. | |
| 1590 | + * | |
| 1591 | + * @param key string | |
| 1592 | + * @param value object | |
| 1593 | + * @return this. | |
| 1594 | + * @throws JSONException | |
| 1595 | + * if the key is a duplicate | |
| 1596 | + */ | |
| 1597 | + public JSONObject putOnce(String key, Object value) throws JSONException { | |
| 1598 | + if (key != null && value != null) { | |
| 1599 | + if (this.opt(key) != null) { | |
| 1600 | + throw new JSONException("Duplicate key \"" + key + "\""); | |
| 1601 | + } | |
| 1602 | + this.put(key, value); | |
| 1603 | + } | |
| 1604 | + return this; | |
| 1605 | + } | |
| 1606 | + | |
| 1607 | + /** | |
| 1608 | + * Put a key/value pair in the JSONObject, but only if the key and the value | |
| 1609 | + * are both non-null. | |
| 1610 | + * | |
| 1611 | + * @param key | |
| 1612 | + * A key string. | |
| 1613 | + * @param value | |
| 1614 | + * An object which is the value. It should be of one of these | |
| 1615 | + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, | |
| 1616 | + * String, or the JSONObject.NULL object. | |
| 1617 | + * @return this. | |
| 1618 | + * @throws JSONException | |
| 1619 | + * If the value is a non-finite number. | |
| 1620 | + */ | |
| 1621 | + public JSONObject putOpt(String key, Object value) throws JSONException { | |
| 1622 | + if (key != null && value != null) { | |
| 1623 | + this.put(key, value); | |
| 1624 | + } | |
| 1625 | + return this; | |
| 1626 | + } | |
| 1627 | + | |
| 1628 | + /** | |
| 1629 | + * Creates a JSONPointer using an initialization string and tries to | |
| 1630 | + * match it to an item within this JSONObject. For example, given a | |
| 1631 | + * JSONObject initialized with this document: | |
| 1632 | + * <pre> | |
| 1633 | + * { | |
| 1634 | + * "a":{"b":"c"} | |
| 1635 | + * } | |
| 1636 | + * </pre> | |
| 1637 | + * and this JSONPointer string: | |
| 1638 | + * <pre> | |
| 1639 | + * "/a/b" | |
| 1640 | + * </pre> | |
| 1641 | + * Then this method will return the String "c". | |
| 1642 | + * A JSONPointerException may be thrown from code called by this method. | |
| 1643 | + * | |
| 1644 | + * @param jsonPointer string that can be used to create a JSONPointer | |
| 1645 | + * @return the item matched by the JSONPointer, otherwise null | |
| 1646 | + */ | |
| 1647 | + public Object query(String jsonPointer) { | |
| 1648 | + return query(new JSONPointer(jsonPointer)); | |
| 1649 | + } | |
| 1650 | + /** | |
| 1651 | + * Uses a user initialized JSONPointer and tries to | |
| 1652 | + * match it to an item within this JSONObject. For example, given a | |
| 1653 | + * JSONObject initialized with this document: | |
| 1654 | + * <pre> | |
| 1655 | + * { | |
| 1656 | + * "a":{"b":"c"} | |
| 1657 | + * } | |
| 1658 | + * </pre> | |
| 1659 | + * and this JSONPointer: | |
| 1660 | + * <pre> | |
| 1661 | + * "/a/b" | |
| 1662 | + * </pre> | |
| 1663 | + * Then this method will return the String "c". | |
| 1664 | + * A JSONPointerException may be thrown from code called by this method. | |
| 1665 | + * | |
| 1666 | + * @param jsonPointer string that can be used to create a JSONPointer | |
| 1667 | + * @return the item matched by the JSONPointer, otherwise null | |
| 1668 | + */ | |
| 1669 | + public Object query(JSONPointer jsonPointer) { | |
| 1670 | + return jsonPointer.queryFrom(this); | |
| 1671 | + } | |
| 1672 | + | |
| 1673 | + /** | |
| 1674 | + * Queries and returns a value from this object using {@code jsonPointer}, or | |
| 1675 | + * returns null if the query fails due to a missing key. | |
| 1676 | + * | |
| 1677 | + * @param jsonPointer the string representation of the JSON pointer | |
| 1678 | + * @return the queried value or {@code null} | |
| 1679 | + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax | |
| 1680 | + */ | |
| 1681 | + public Object optQuery(String jsonPointer) { | |
| 1682 | + return optQuery(new JSONPointer(jsonPointer)); | |
| 1683 | + } | |
| 1684 | + | |
| 1685 | + /** | |
| 1686 | + * Queries and returns a value from this object using {@code jsonPointer}, or | |
| 1687 | + * returns null if the query fails due to a missing key. | |
| 1688 | + * | |
| 1689 | + * @param jsonPointer The JSON pointer | |
| 1690 | + * @return the queried value or {@code null} | |
| 1691 | + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax | |
| 1692 | + */ | |
| 1693 | + public Object optQuery(JSONPointer jsonPointer) { | |
| 1694 | + try { | |
| 1695 | + return jsonPointer.queryFrom(this); | |
| 1696 | + } catch (JSONPointerException e) { | |
| 1697 | + return null; | |
| 1698 | + } | |
| 1699 | + } | |
| 1700 | + | |
| 1701 | + /** | |
| 1702 | + * Produce a string in double quotes with backslash sequences in all the | |
| 1703 | + * right places. A backslash will be inserted within </, producing <\/, | |
| 1704 | + * allowing JSON text to be delivered in HTML. In JSON text, a string cannot | |
| 1705 | + * contain a control character or an unescaped quote or backslash. | |
| 1706 | + * | |
| 1707 | + * @param string | |
| 1708 | + * A String | |
| 1709 | + * @return A String correctly formatted for insertion in a JSON text. | |
| 1710 | + */ | |
| 1711 | + public static String quote(String string) { | |
| 1712 | + StringWriter sw = new StringWriter(); | |
| 1713 | + synchronized (sw.getBuffer()) { | |
| 1714 | + try { | |
| 1715 | + return quote(string, sw).toString(); | |
| 1716 | + } catch (IOException ignored) { | |
| 1717 | + // will never happen - we are writing to a string writer | |
| 1718 | + return ""; | |
| 1719 | + } | |
| 1720 | + } | |
| 1721 | + } | |
| 1722 | + | |
| 1723 | + public static Writer quote(String string, Writer w) throws IOException { | |
| 1724 | + if (string == null || string.length() == 0) { | |
| 1725 | + w.write("\"\""); | |
| 1726 | + return w; | |
| 1727 | + } | |
| 1728 | + | |
| 1729 | + char b; | |
| 1730 | + char c = 0; | |
| 1731 | + String hhhh; | |
| 1732 | + int i; | |
| 1733 | + int len = string.length(); | |
| 1734 | + | |
| 1735 | + w.write('"'); | |
| 1736 | + for (i = 0; i < len; i += 1) { | |
| 1737 | + b = c; | |
| 1738 | + c = string.charAt(i); | |
| 1739 | + switch (c) { | |
| 1740 | + case '\\': | |
| 1741 | + case '"': | |
| 1742 | + w.write('\\'); | |
| 1743 | + w.write(c); | |
| 1744 | + break; | |
| 1745 | + case '/': | |
| 1746 | + if (b == '<') { | |
| 1747 | + w.write('\\'); | |
| 1748 | + } | |
| 1749 | + w.write(c); | |
| 1750 | + break; | |
| 1751 | + case '\b': | |
| 1752 | + w.write("\\b"); | |
| 1753 | + break; | |
| 1754 | + case '\t': | |
| 1755 | + w.write("\\t"); | |
| 1756 | + break; | |
| 1757 | + case '\n': | |
| 1758 | + w.write("\\n"); | |
| 1759 | + break; | |
| 1760 | + case '\f': | |
| 1761 | + w.write("\\f"); | |
| 1762 | + break; | |
| 1763 | + case '\r': | |
| 1764 | + w.write("\\r"); | |
| 1765 | + break; | |
| 1766 | + default: | |
| 1767 | + if (c < ' ' || (c >= '\u0080' && c < '\u00a0') | |
| 1768 | + || (c >= '\u2000' && c < '\u2100')) { | |
| 1769 | + w.write("\\u"); | |
| 1770 | + hhhh = Integer.toHexString(c); | |
| 1771 | + w.write("0000", 0, 4 - hhhh.length()); | |
| 1772 | + w.write(hhhh); | |
| 1773 | + } else { | |
| 1774 | + w.write(c); | |
| 1775 | + } | |
| 1776 | + } | |
| 1777 | + } | |
| 1778 | + w.write('"'); | |
| 1779 | + return w; | |
| 1780 | + } | |
| 1781 | + | |
| 1782 | + /** | |
| 1783 | + * Remove a name and its value, if present. | |
| 1784 | + * | |
| 1785 | + * @param key | |
| 1786 | + * The name to be removed. | |
| 1787 | + * @return The value that was associated with the name, or null if there was | |
| 1788 | + * no value. | |
| 1789 | + */ | |
| 1790 | + public Object remove(String key) { | |
| 1791 | + return this.map.remove(key); | |
| 1792 | + } | |
| 1793 | + | |
| 1794 | + /** | |
| 1795 | + * Determine if two JSONObjects are similar. | |
| 1796 | + * They must contain the same set of names which must be associated with | |
| 1797 | + * similar values. | |
| 1798 | + * | |
| 1799 | + * @param other The other JSONObject | |
| 1800 | + * @return true if they are equal | |
| 1801 | + */ | |
| 1802 | + public boolean similar(Object other) { | |
| 1803 | + try { | |
| 1804 | + if (!(other instanceof JSONObject)) { | |
| 1805 | + return false; | |
| 1806 | + } | |
| 1807 | + if (!this.keySet().equals(((JSONObject)other).keySet())) { | |
| 1808 | + return false; | |
| 1809 | + } | |
| 1810 | + for (final Entry<String,?> entry : this.entrySet()) { | |
| 1811 | + String name = entry.getKey(); | |
| 1812 | + Object valueThis = entry.getValue(); | |
| 1813 | + Object valueOther = ((JSONObject)other).get(name); | |
| 1814 | + if(valueThis == valueOther) { | |
| 1815 | + continue; | |
| 1816 | + } | |
| 1817 | + if(valueThis == null) { | |
| 1818 | + return false; | |
| 1819 | + } | |
| 1820 | + if (valueThis instanceof JSONObject) { | |
| 1821 | + if (!((JSONObject)valueThis).similar(valueOther)) { | |
| 1822 | + return false; | |
| 1823 | + } | |
| 1824 | + } else if (valueThis instanceof JSONArray) { | |
| 1825 | + if (!((JSONArray)valueThis).similar(valueOther)) { | |
| 1826 | + return false; | |
| 1827 | + } | |
| 1828 | + } else if (!valueThis.equals(valueOther)) { | |
| 1829 | + return false; | |
| 1830 | + } | |
| 1831 | + } | |
| 1832 | + return true; | |
| 1833 | + } catch (Throwable exception) { | |
| 1834 | + return false; | |
| 1835 | + } | |
| 1836 | + } | |
| 1837 | + | |
| 1838 | + /** | |
| 1839 | + * Tests if the value should be tried as a decimal. It makes no test if there are actual digits. | |
| 1840 | + * | |
| 1841 | + * @param val value to test | |
| 1842 | + * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise. | |
| 1843 | + */ | |
| 1844 | + protected static boolean isDecimalNotation(final String val) { | |
| 1845 | + return val.indexOf('.') > -1 || val.indexOf('e') > -1 | |
| 1846 | + || val.indexOf('E') > -1 || "-0".equals(val); | |
| 1847 | + } | |
| 1848 | + | |
| 1849 | + /** | |
| 1850 | + * Converts a string to a number using the narrowest possible type. Possible | |
| 1851 | + * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer. | |
| 1852 | + * When a Double is returned, it should always be a valid Double and not NaN or +-infinity. | |
| 1853 | + * | |
| 1854 | + * @param val value to convert | |
| 1855 | + * @return Number representation of the value. | |
| 1856 | + * @throws NumberFormatException thrown if the value is not a valid number. A public | |
| 1857 | + * caller should catch this and wrap it in a {@link JSONException} if applicable. | |
| 1858 | + */ | |
| 1859 | + protected static Number stringToNumber(final String val) throws NumberFormatException { | |
| 1860 | + char initial = val.charAt(0); | |
| 1861 | + if ((initial >= '0' && initial <= '9') || initial == '-') { | |
| 1862 | + // decimal representation | |
| 1863 | + if (isDecimalNotation(val)) { | |
| 1864 | + // quick dirty way to see if we need a BigDecimal instead of a Double | |
| 1865 | + // this only handles some cases of overflow or underflow | |
| 1866 | + if (val.length()>14) { | |
| 1867 | + return new BigDecimal(val); | |
| 1868 | + } | |
| 1869 | + final Double d = Double.valueOf(val); | |
| 1870 | + if (d.isInfinite() || d.isNaN()) { | |
| 1871 | + // if we can't parse it as a double, go up to BigDecimal | |
| 1872 | + // this is probably due to underflow like 4.32e-678 | |
| 1873 | + // or overflow like 4.65e5324. The size of the string is small | |
| 1874 | + // but can't be held in a Double. | |
| 1875 | + return new BigDecimal(val); | |
| 1876 | + } | |
| 1877 | + return d; | |
| 1878 | + } | |
| 1879 | + // integer representation. | |
| 1880 | + // This will narrow any values to the smallest reasonable Object representation | |
| 1881 | + // (Integer, Long, or BigInteger) | |
| 1882 | + | |
| 1883 | + // string version | |
| 1884 | + // The compare string length method reduces GC, | |
| 1885 | + // but leads to smaller integers being placed in larger wrappers even though not | |
| 1886 | + // needed. i.e. 1,000,000,000 -> Long even though it's an Integer | |
| 1887 | + // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long | |
| 1888 | + //if(val.length()<=9){ | |
| 1889 | + // return Integer.valueOf(val); | |
| 1890 | + //} | |
| 1891 | + //if(val.length()<=18){ | |
| 1892 | + // return Long.valueOf(val); | |
| 1893 | + //} | |
| 1894 | + //return new BigInteger(val); | |
| 1895 | + | |
| 1896 | + // BigInteger version: We use a similar bitLenth compare as | |
| 1897 | + // BigInteger#intValueExact uses. Increases GC, but objects hold | |
| 1898 | + // only what they need. i.e. Less runtime overhead if the value is | |
| 1899 | + // long lived. Which is the better tradeoff? This is closer to what's | |
| 1900 | + // in stringToValue. | |
| 1901 | + BigInteger bi = new BigInteger(val); | |
| 1902 | + if(bi.bitLength()<=31){ | |
| 1903 | + return Integer.valueOf(bi.intValue()); | |
| 1904 | + } | |
| 1905 | + if(bi.bitLength()<=63){ | |
| 1906 | + return Long.valueOf(bi.longValue()); | |
| 1907 | + } | |
| 1908 | + return bi; | |
| 1909 | + } | |
| 1910 | + throw new NumberFormatException("val ["+val+"] is not a valid number."); | |
| 1911 | + } | |
| 1912 | + | |
| 1913 | + /** | |
| 1914 | + * Try to convert a string into a number, boolean, or null. If the string | |
| 1915 | + * can't be converted, return the string. | |
| 1916 | + * | |
| 1917 | + * @param string | |
| 1918 | + * A String. | |
| 1919 | + * @return A simple JSON value. | |
| 1920 | + */ | |
| 1921 | + // Changes to this method must be copied to the corresponding method in | |
| 1922 | + // the XML class to keep full support for Android | |
| 1923 | + public static Object stringToValue(String string) { | |
| 1924 | + if (string.equals("")) { | |
| 1925 | + return string; | |
| 1926 | + } | |
| 1927 | + if (string.equalsIgnoreCase("true")) { | |
| 1928 | + return Boolean.TRUE; | |
| 1929 | + } | |
| 1930 | + if (string.equalsIgnoreCase("false")) { | |
| 1931 | + return Boolean.FALSE; | |
| 1932 | + } | |
| 1933 | + if (string.equalsIgnoreCase("null")) { | |
| 1934 | + return JSONObject.NULL; | |
| 1935 | + } | |
| 1936 | + | |
| 1937 | + /* | |
| 1938 | + * If it might be a number, try converting it. If a number cannot be | |
| 1939 | + * produced, then the value will just be a string. | |
| 1940 | + */ | |
| 1941 | + | |
| 1942 | + char initial = string.charAt(0); | |
| 1943 | + if ((initial >= '0' && initial <= '9') || initial == '-') { | |
| 1944 | + try { | |
| 1945 | + // if we want full Big Number support this block can be replaced with: | |
| 1946 | + // return stringToNumber(string); | |
| 1947 | + if (isDecimalNotation(string)) { | |
| 1948 | + Double d = Double.valueOf(string); | |
| 1949 | + if (!d.isInfinite() && !d.isNaN()) { | |
| 1950 | + return d; | |
| 1951 | + } | |
| 1952 | + } else { | |
| 1953 | + Long myLong = Long.valueOf(string); | |
| 1954 | + if (string.equals(myLong.toString())) { | |
| 1955 | + if (myLong.longValue() == myLong.intValue()) { | |
| 1956 | + return Integer.valueOf(myLong.intValue()); | |
| 1957 | + } | |
| 1958 | + return myLong; | |
| 1959 | + } | |
| 1960 | + } | |
| 1961 | + } catch (Exception ignore) { | |
| 1962 | + } | |
| 1963 | + } | |
| 1964 | + return string; | |
| 1965 | + } | |
| 1966 | + | |
| 1967 | + /** | |
| 1968 | + * Throw an exception if the object is a NaN or infinite number. | |
| 1969 | + * | |
| 1970 | + * @param o | |
| 1971 | + * The object to test. | |
| 1972 | + * @throws JSONException | |
| 1973 | + * If o is a non-finite number. | |
| 1974 | + */ | |
| 1975 | + public static void testValidity(Object o) throws JSONException { | |
| 1976 | + if (o != null) { | |
| 1977 | + if (o instanceof Double) { | |
| 1978 | + if (((Double) o).isInfinite() || ((Double) o).isNaN()) { | |
| 1979 | + throw new JSONException( | |
| 1980 | + "JSON does not allow non-finite numbers."); | |
| 1981 | + } | |
| 1982 | + } else if (o instanceof Float) { | |
| 1983 | + if (((Float) o).isInfinite() || ((Float) o).isNaN()) { | |
| 1984 | + throw new JSONException( | |
| 1985 | + "JSON does not allow non-finite numbers."); | |
| 1986 | + } | |
| 1987 | + } | |
| 1988 | + } | |
| 1989 | + } | |
| 1990 | + | |
| 1991 | + /** | |
| 1992 | + * Produce a JSONArray containing the values of the members of this | |
| 1993 | + * JSONObject. | |
| 1994 | + * | |
| 1995 | + * @param names | |
| 1996 | + * A JSONArray containing a list of key strings. This determines | |
| 1997 | + * the sequence of the values in the result. | |
| 1998 | + * @return A JSONArray of values. | |
| 1999 | + * @throws JSONException | |
| 2000 | + * If any of the values are non-finite numbers. | |
| 2001 | + */ | |
| 2002 | + public JSONArray toJSONArray(JSONArray names) throws JSONException { | |
| 2003 | + if (names == null || names.length() == 0) { | |
| 2004 | + return null; | |
| 2005 | + } | |
| 2006 | + JSONArray ja = new JSONArray(); | |
| 2007 | + for (int i = 0; i < names.length(); i += 1) { | |
| 2008 | + ja.put(this.opt(names.getString(i))); | |
| 2009 | + } | |
| 2010 | + return ja; | |
| 2011 | + } | |
| 2012 | + | |
| 2013 | + /** | |
| 2014 | + * Make a JSON text of this JSONObject. For compactness, no whitespace is | |
| 2015 | + * added. If this would not result in a syntactically correct JSON text, | |
| 2016 | + * then null will be returned instead. | |
| 2017 | + * <p><b> | |
| 2018 | + * Warning: This method assumes that the data structure is acyclical. | |
| 2019 | + * </b> | |
| 2020 | + * | |
| 2021 | + * @return a printable, displayable, portable, transmittable representation | |
| 2022 | + * of the object, beginning with <code>{</code> <small>(left | |
| 2023 | + * brace)</small> and ending with <code>}</code> <small>(right | |
| 2024 | + * brace)</small>. | |
| 2025 | + */ | |
| 2026 | + @Override | |
| 2027 | + public String toString() { | |
| 2028 | + try { | |
| 2029 | + return this.toString(0); | |
| 2030 | + } catch (Exception e) { | |
| 2031 | + return null; | |
| 2032 | + } | |
| 2033 | + } | |
| 2034 | + | |
| 2035 | + /** | |
| 2036 | + * Make a pretty-printed JSON text of this JSONObject. | |
| 2037 | + * | |
| 2038 | + * <p>If <code>indentFactor > 0</code> and the {@link JSONObject} | |
| 2039 | + * has only one key, then the object will be output on a single line: | |
| 2040 | + * <pre>{@code {"key": 1}}</pre> | |
| 2041 | + * | |
| 2042 | + * <p>If an object has 2 or more keys, then it will be output across | |
| 2043 | + * multiple lines: <code><pre>{ | |
| 2044 | + * "key1": 1, | |
| 2045 | + * "key2": "value 2", | |
| 2046 | + * "key3": 3 | |
| 2047 | + * }</pre></code> | |
| 2048 | + * <p><b> | |
| 2049 | + * Warning: This method assumes that the data structure is acyclical. | |
| 2050 | + * </b> | |
| 2051 | + * | |
| 2052 | + * @param indentFactor | |
| 2053 | + * The number of spaces to add to each level of indentation. | |
| 2054 | + * @return a printable, displayable, portable, transmittable representation | |
| 2055 | + * of the object, beginning with <code>{</code> <small>(left | |
| 2056 | + * brace)</small> and ending with <code>}</code> <small>(right | |
| 2057 | + * brace)</small>. | |
| 2058 | + * @throws JSONException | |
| 2059 | + * If the object contains an invalid number. | |
| 2060 | + */ | |
| 2061 | + public String toString(int indentFactor) throws JSONException { | |
| 2062 | + StringWriter w = new StringWriter(); | |
| 2063 | + synchronized (w.getBuffer()) { | |
| 2064 | + return this.write(w, indentFactor, 0).toString(); | |
| 2065 | + } | |
| 2066 | + } | |
| 2067 | + | |
| 2068 | + /** | |
| 2069 | + * Make a JSON text of an Object value. If the object has an | |
| 2070 | + * value.toJSONString() method, then that method will be used to produce the | |
| 2071 | + * JSON text. The method is required to produce a strictly conforming text. | |
| 2072 | + * If the object does not contain a toJSONString method (which is the most | |
| 2073 | + * common case), then a text will be produced by other means. If the value | |
| 2074 | + * is an array or Collection, then a JSONArray will be made from it and its | |
| 2075 | + * toJSONString method will be called. If the value is a MAP, then a | |
| 2076 | + * JSONObject will be made from it and its toJSONString method will be | |
| 2077 | + * called. Otherwise, the value's toString method will be called, and the | |
| 2078 | + * result will be quoted. | |
| 2079 | + * | |
| 2080 | + * <p> | |
| 2081 | + * Warning: This method assumes that the data structure is acyclical. | |
| 2082 | + * | |
| 2083 | + * @param value | |
| 2084 | + * The value to be serialized. | |
| 2085 | + * @return a printable, displayable, transmittable representation of the | |
| 2086 | + * object, beginning with <code>{</code> <small>(left | |
| 2087 | + * brace)</small> and ending with <code>}</code> <small>(right | |
| 2088 | + * brace)</small>. | |
| 2089 | + * @throws JSONException | |
| 2090 | + * If the value is or contains an invalid number. | |
| 2091 | + */ | |
| 2092 | + public static String valueToString(Object value) throws JSONException { | |
| 2093 | + // moves the implementation to JSONWriter as: | |
| 2094 | + // 1. It makes more sense to be part of the writer class | |
| 2095 | + // 2. For Android support this method is not available. By implementing it in the Writer | |
| 2096 | + // Android users can use the writer with the built in Android JSONObject implementation. | |
| 2097 | + return JSONWriter.valueToString(value); | |
| 2098 | + } | |
| 2099 | + | |
| 2100 | + /** | |
| 2101 | + * Wrap an object, if necessary. If the object is null, return the NULL | |
| 2102 | + * object. If it is an array or collection, wrap it in a JSONArray. If it is | |
| 2103 | + * a map, wrap it in a JSONObject. If it is a standard property (Double, | |
| 2104 | + * String, et al) then it is already wrapped. Otherwise, if it comes from | |
| 2105 | + * one of the java packages, turn it into a string. And if it doesn't, try | |
| 2106 | + * to wrap it in a JSONObject. If the wrapping fails, then null is returned. | |
| 2107 | + * | |
| 2108 | + * @param object | |
| 2109 | + * The object to wrap | |
| 2110 | + * @return The wrapped value | |
| 2111 | + */ | |
| 2112 | + public static Object wrap(Object object) { | |
| 2113 | + try { | |
| 2114 | + if (object == null) { | |
| 2115 | + return NULL; | |
| 2116 | + } | |
| 2117 | + if (object instanceof JSONObject || object instanceof JSONArray | |
| 2118 | + || NULL.equals(object) || object instanceof JSONString | |
| 2119 | + || object instanceof Byte || object instanceof Character | |
| 2120 | + || object instanceof Short || object instanceof Integer | |
| 2121 | + || object instanceof Long || object instanceof Boolean | |
| 2122 | + || object instanceof Float || object instanceof Double | |
| 2123 | + || object instanceof String || object instanceof BigInteger | |
| 2124 | + || object instanceof BigDecimal || object instanceof Enum) { | |
| 2125 | + return object; | |
| 2126 | + } | |
| 2127 | + | |
| 2128 | + if (object instanceof Collection) { | |
| 2129 | + Collection<?> coll = (Collection<?>) object; | |
| 2130 | + return new JSONArray(coll); | |
| 2131 | + } | |
| 2132 | + if (object.getClass().isArray()) { | |
| 2133 | + return new JSONArray(object); | |
| 2134 | + } | |
| 2135 | + if (object instanceof Map) { | |
| 2136 | + Map<?, ?> map = (Map<?, ?>) object; | |
| 2137 | + return new JSONObject(map); | |
| 2138 | + } | |
| 2139 | + Package objectPackage = object.getClass().getPackage(); | |
| 2140 | + String objectPackageName = objectPackage != null ? objectPackage | |
| 2141 | + .getName() : ""; | |
| 2142 | + if (objectPackageName.startsWith("java.") | |
| 2143 | + || objectPackageName.startsWith("javax.") | |
| 2144 | + || object.getClass().getClassLoader() == null) { | |
| 2145 | + return object.toString(); | |
| 2146 | + } | |
| 2147 | + return new JSONObject(object); | |
| 2148 | + } catch (Exception exception) { | |
| 2149 | + return null; | |
| 2150 | + } | |
| 2151 | + } | |
| 2152 | + | |
| 2153 | + /** | |
| 2154 | + * Write the contents of the JSONObject as JSON text to a writer. For | |
| 2155 | + * compactness, no whitespace is added. | |
| 2156 | + * <p><b> | |
| 2157 | + * Warning: This method assumes that the data structure is acyclical. | |
| 2158 | + * </b> | |
| 2159 | + * | |
| 2160 | + * @return The writer. | |
| 2161 | + * @throws JSONException | |
| 2162 | + */ | |
| 2163 | + public Writer write(Writer writer) throws JSONException { | |
| 2164 | + return this.write(writer, 0, 0); | |
| 2165 | + } | |
| 2166 | + | |
| 2167 | + static final Writer writeValue(Writer writer, Object value, | |
| 2168 | + int indentFactor, int indent) throws JSONException, IOException { | |
| 2169 | + if (value == null || value.equals(null)) { | |
| 2170 | + writer.write("null"); | |
| 2171 | + } else if (value instanceof JSONString) { | |
| 2172 | + Object o; | |
| 2173 | + try { | |
| 2174 | + o = ((JSONString) value).toJSONString(); | |
| 2175 | + } catch (Exception e) { | |
| 2176 | + throw new JSONException(e); | |
| 2177 | + } | |
| 2178 | + writer.write(o != null ? o.toString() : quote(value.toString())); | |
| 2179 | + } else if (value instanceof Number) { | |
| 2180 | + // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary | |
| 2181 | + final String numberAsString = numberToString((Number) value); | |
| 2182 | + try { | |
| 2183 | + // Use the BigDecimal constructor for its parser to validate the format. | |
| 2184 | + @SuppressWarnings("unused") | |
| 2185 | + BigDecimal testNum = new BigDecimal(numberAsString); | |
| 2186 | + // Close enough to a JSON number that we will use it unquoted | |
| 2187 | + writer.write(numberAsString); | |
| 2188 | + } catch (NumberFormatException ex){ | |
| 2189 | + // The Number value is not a valid JSON number. | |
| 2190 | + // Instead we will quote it as a string | |
| 2191 | + quote(numberAsString, writer); | |
| 2192 | + } | |
| 2193 | + } else if (value instanceof Boolean) { | |
| 2194 | + writer.write(value.toString()); | |
| 2195 | + } else if (value instanceof Enum<?>) { | |
| 2196 | + writer.write(quote(((Enum<?>)value).name())); | |
| 2197 | + } else if (value instanceof JSONObject) { | |
| 2198 | + ((JSONObject) value).write(writer, indentFactor, indent); | |
| 2199 | + } else if (value instanceof JSONArray) { | |
| 2200 | + ((JSONArray) value).write(writer, indentFactor, indent); | |
| 2201 | + } else if (value instanceof Map) { | |
| 2202 | + Map<?, ?> map = (Map<?, ?>) value; | |
| 2203 | + new JSONObject(map).write(writer, indentFactor, indent); | |
| 2204 | + } else if (value instanceof Collection) { | |
| 2205 | + Collection<?> coll = (Collection<?>) value; | |
| 2206 | + new JSONArray(coll).write(writer, indentFactor, indent); | |
| 2207 | + } else if (value.getClass().isArray()) { | |
| 2208 | + new JSONArray(value).write(writer, indentFactor, indent); | |
| 2209 | + } else { | |
| 2210 | + quote(value.toString(), writer); | |
| 2211 | + } | |
| 2212 | + return writer; | |
| 2213 | + } | |
| 2214 | + | |
| 2215 | + static final void indent(Writer writer, int indent) throws IOException { | |
| 2216 | + for (int i = 0; i < indent; i += 1) { | |
| 2217 | + writer.write(' '); | |
| 2218 | + } | |
| 2219 | + } | |
| 2220 | + | |
| 2221 | + /** | |
| 2222 | + * Write the contents of the JSONObject as JSON text to a writer. | |
| 2223 | + * | |
| 2224 | + * <p>If <code>indentFactor > 0</code> and the {@link JSONObject} | |
| 2225 | + * has only one key, then the object will be output on a single line: | |
| 2226 | + * <pre>{@code {"key": 1}}</pre> | |
| 2227 | + * | |
| 2228 | + * <p>If an object has 2 or more keys, then it will be output across | |
| 2229 | + * multiple lines: <code><pre>{ | |
| 2230 | + * "key1": 1, | |
| 2231 | + * "key2": "value 2", | |
| 2232 | + * "key3": 3 | |
| 2233 | + * }</pre></code> | |
| 2234 | + * <p><b> | |
| 2235 | + * Warning: This method assumes that the data structure is acyclical. | |
| 2236 | + * </b> | |
| 2237 | + * | |
| 2238 | + * @param writer | |
| 2239 | + * Writes the serialized JSON | |
| 2240 | + * @param indentFactor | |
| 2241 | + * The number of spaces to add to each level of indentation. | |
| 2242 | + * @param indent | |
| 2243 | + * The indentation of the top level. | |
| 2244 | + * @return The writer. | |
| 2245 | + * @throws JSONException | |
| 2246 | + */ | |
| 2247 | + public Writer write(Writer writer, int indentFactor, int indent) | |
| 2248 | + throws JSONException { | |
| 2249 | + try { | |
| 2250 | + boolean commanate = false; | |
| 2251 | + final int length = this.length(); | |
| 2252 | + writer.write('{'); | |
| 2253 | + | |
| 2254 | + if (length == 1) { | |
| 2255 | + final Entry<String,?> entry = this.entrySet().iterator().next(); | |
| 2256 | + final String key = entry.getKey(); | |
| 2257 | + writer.write(quote(key)); | |
| 2258 | + writer.write(':'); | |
| 2259 | + if (indentFactor > 0) { | |
| 2260 | + writer.write(' '); | |
| 2261 | + } | |
| 2262 | + try{ | |
| 2263 | + writeValue(writer, entry.getValue(), indentFactor, indent); | |
| 2264 | + } catch (Exception e) { | |
| 2265 | + throw new JSONException("Unable to write JSONObject value for key: " + key, e); | |
| 2266 | + } | |
| 2267 | + } else if (length != 0) { | |
| 2268 | + final int newindent = indent + indentFactor; | |
| 2269 | + for (final Entry<String,?> entry : this.entrySet()) { | |
| 2270 | + if (commanate) { | |
| 2271 | + writer.write(','); | |
| 2272 | + } | |
| 2273 | + if (indentFactor > 0) { | |
| 2274 | + writer.write('\n'); | |
| 2275 | + } | |
| 2276 | + indent(writer, newindent); | |
| 2277 | + final String key = entry.getKey(); | |
| 2278 | + writer.write(quote(key)); | |
| 2279 | + writer.write(':'); | |
| 2280 | + if (indentFactor > 0) { | |
| 2281 | + writer.write(' '); | |
| 2282 | + } | |
| 2283 | + try { | |
| 2284 | + writeValue(writer, entry.getValue(), indentFactor, newindent); | |
| 2285 | + } catch (Exception e) { | |
| 2286 | + throw new JSONException("Unable to write JSONObject value for key: " + key, e); | |
| 2287 | + } | |
| 2288 | + commanate = true; | |
| 2289 | + } | |
| 2290 | + if (indentFactor > 0) { | |
| 2291 | + writer.write('\n'); | |
| 2292 | + } | |
| 2293 | + indent(writer, indent); | |
| 2294 | + } | |
| 2295 | + writer.write('}'); | |
| 2296 | + return writer; | |
| 2297 | + } catch (IOException exception) { | |
| 2298 | + throw new JSONException(exception); | |
| 2299 | + } | |
| 2300 | + } | |
| 2301 | + | |
| 2302 | + /** | |
| 2303 | + * Returns a java.util.Map containing all of the entries in this object. | |
| 2304 | + * If an entry in the object is a JSONArray or JSONObject it will also | |
| 2305 | + * be converted. | |
| 2306 | + * <p> | |
| 2307 | + * Warning: This method assumes that the data structure is acyclical. | |
| 2308 | + * | |
| 2309 | + * @return a java.util.Map containing the entries of this object | |
| 2310 | + */ | |
| 2311 | + public Map<String, Object> toMap() { | |
| 2312 | + Map<String, Object> results = new HashMap<String, Object>(); | |
| 2313 | + for (Entry<String, Object> entry : this.entrySet()) { | |
| 2314 | + Object value; | |
| 2315 | + if (entry.getValue() == null || NULL.equals(entry.getValue())) { | |
| 2316 | + value = null; | |
| 2317 | + } else if (entry.getValue() instanceof JSONObject) { | |
| 2318 | + value = ((JSONObject) entry.getValue()).toMap(); | |
| 2319 | + } else if (entry.getValue() instanceof JSONArray) { | |
| 2320 | + value = ((JSONArray) entry.getValue()).toList(); | |
| 2321 | + } else { | |
| 2322 | + value = entry.getValue(); | |
| 2323 | + } | |
| 2324 | + results.put(entry.getKey(), value); | |
| 2325 | + } | |
| 2326 | + return results; | |
| 2327 | + } | |
| 2328 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONPointer.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +import java.io.UnsupportedEncodingException; | |
| 4 | +import java.net.URLDecoder; | |
| 5 | +import java.net.URLEncoder; | |
| 6 | +import java.util.ArrayList; | |
| 7 | +import java.util.Collections; | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +import static java.lang.String.format; | |
| 11 | + | |
| 12 | +/* | |
| 13 | +Copyright (c) 2002 JSON.org | |
| 14 | + | |
| 15 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 16 | +of this software and associated documentation files (the "Software"), to deal | |
| 17 | +in the Software without restriction, including without limitation the rights | |
| 18 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 19 | +copies of the Software, and to permit persons to whom the Software is | |
| 20 | +furnished to do so, subject to the following conditions: | |
| 21 | + | |
| 22 | +The above copyright notice and this permission notice shall be included in all | |
| 23 | +copies or substantial portions of the Software. | |
| 24 | + | |
| 25 | +The Software shall be used for Good, not Evil. | |
| 26 | + | |
| 27 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 28 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 29 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 30 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 31 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 32 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 33 | +SOFTWARE. | |
| 34 | +*/ | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * A JSON Pointer is a simple query language defined for JSON documents by | |
| 38 | + * <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>. | |
| 39 | + * | |
| 40 | + * In a nutshell, JSONPointer allows the user to navigate into a JSON document | |
| 41 | + * using strings, and retrieve targeted objects, like a simple form of XPATH. | |
| 42 | + * Path segments are separated by the '/' char, which signifies the root of | |
| 43 | + * the document when it appears as the first char of the string. Array | |
| 44 | + * elements are navigated using ordinals, counting from 0. JSONPointer strings | |
| 45 | + * may be extended to any arbitrary number of segments. If the navigation | |
| 46 | + * is successful, the matched item is returned. A matched item may be a | |
| 47 | + * JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building | |
| 48 | + * fails, an appropriate exception is thrown. If the navigation fails to find | |
| 49 | + * a match, a JSONPointerException is thrown. | |
| 50 | + * | |
| 51 | + * @author JSON.org | |
| 52 | + * @version 2016-05-14 | |
| 53 | + */ | |
| 54 | +public class JSONPointer { | |
| 55 | + | |
| 56 | + // used for URL encoding and decoding | |
| 57 | + private static final String ENCODING = "utf-8"; | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * This class allows the user to build a JSONPointer in steps, using | |
| 61 | + * exactly one segment in each step. | |
| 62 | + */ | |
| 63 | + public static class Builder { | |
| 64 | + | |
| 65 | + // Segments for the eventual JSONPointer string | |
| 66 | + private final List<String> refTokens = new ArrayList<String>(); | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Creates a {@code JSONPointer} instance using the tokens previously set using the | |
| 70 | + * {@link #append(String)} method calls. | |
| 71 | + */ | |
| 72 | + public JSONPointer build() { | |
| 73 | + return new JSONPointer(this.refTokens); | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Adds an arbitrary token to the list of reference tokens. It can be any non-null value. | |
| 78 | + * | |
| 79 | + * Unlike in the case of JSON string or URI fragment representation of JSON pointers, the | |
| 80 | + * argument of this method MUST NOT be escaped. If you want to query the property called | |
| 81 | + * {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no | |
| 82 | + * need to escape it as {@code "a~0b"}. | |
| 83 | + * | |
| 84 | + * @param token the new token to be appended to the list | |
| 85 | + * @return {@code this} | |
| 86 | + * @throws NullPointerException if {@code token} is null | |
| 87 | + */ | |
| 88 | + public Builder append(String token) { | |
| 89 | + if (token == null) { | |
| 90 | + throw new NullPointerException("token cannot be null"); | |
| 91 | + } | |
| 92 | + this.refTokens.add(token); | |
| 93 | + return this; | |
| 94 | + } | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * Adds an integer to the reference token list. Although not necessarily, mostly this token will | |
| 98 | + * denote an array index. | |
| 99 | + * | |
| 100 | + * @param arrayIndex the array index to be added to the token list | |
| 101 | + * @return {@code this} | |
| 102 | + */ | |
| 103 | + public Builder append(int arrayIndex) { | |
| 104 | + this.refTokens.add(String.valueOf(arrayIndex)); | |
| 105 | + return this; | |
| 106 | + } | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Static factory method for {@link Builder}. Example usage: | |
| 111 | + * | |
| 112 | + * <pre><code> | |
| 113 | + * JSONPointer pointer = JSONPointer.builder() | |
| 114 | + * .append("obj") | |
| 115 | + * .append("other~key").append("another/key") | |
| 116 | + * .append("\"") | |
| 117 | + * .append(0) | |
| 118 | + * .build(); | |
| 119 | + * </code></pre> | |
| 120 | + * | |
| 121 | + * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained | |
| 122 | + * {@link Builder#append(String)} calls. | |
| 123 | + */ | |
| 124 | + public static Builder builder() { | |
| 125 | + return new Builder(); | |
| 126 | + } | |
| 127 | + | |
| 128 | + // Segments for the JSONPointer string | |
| 129 | + private final List<String> refTokens; | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * Pre-parses and initializes a new {@code JSONPointer} instance. If you want to | |
| 133 | + * evaluate the same JSON Pointer on different JSON documents then it is recommended | |
| 134 | + * to keep the {@code JSONPointer} instances due to performance considerations. | |
| 135 | + * | |
| 136 | + * @param pointer the JSON String or URI Fragment representation of the JSON pointer. | |
| 137 | + * @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer | |
| 138 | + */ | |
| 139 | + public JSONPointer(final String pointer) { | |
| 140 | + if (pointer == null) { | |
| 141 | + throw new NullPointerException("pointer cannot be null"); | |
| 142 | + } | |
| 143 | + if (pointer.isEmpty() || pointer.equals("#")) { | |
| 144 | + this.refTokens = Collections.emptyList(); | |
| 145 | + return; | |
| 146 | + } | |
| 147 | + String refs; | |
| 148 | + if (pointer.startsWith("#/")) { | |
| 149 | + refs = pointer.substring(2); | |
| 150 | + try { | |
| 151 | + refs = URLDecoder.decode(refs, ENCODING); | |
| 152 | + } catch (UnsupportedEncodingException e) { | |
| 153 | + throw new RuntimeException(e); | |
| 154 | + } | |
| 155 | + } else if (pointer.startsWith("/")) { | |
| 156 | + refs = pointer.substring(1); | |
| 157 | + } else { | |
| 158 | + throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); | |
| 159 | + } | |
| 160 | + this.refTokens = new ArrayList<String>(); | |
| 161 | + for (String token : refs.split("/")) { | |
| 162 | + this.refTokens.add(unescape(token)); | |
| 163 | + } | |
| 164 | + } | |
| 165 | + | |
| 166 | + public JSONPointer(List<String> refTokens) { | |
| 167 | + this.refTokens = new ArrayList<String>(refTokens); | |
| 168 | + } | |
| 169 | + | |
| 170 | + private String unescape(String token) { | |
| 171 | + return token.replace("~1", "/").replace("~0", "~") | |
| 172 | + .replace("\\\"", "\"") | |
| 173 | + .replace("\\\\", "\\"); | |
| 174 | + } | |
| 175 | + | |
| 176 | + /** | |
| 177 | + * Evaluates this JSON Pointer on the given {@code document}. The {@code document} | |
| 178 | + * is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty | |
| 179 | + * JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the | |
| 180 | + * returned value will be {@code document} itself. | |
| 181 | + * | |
| 182 | + * @param document the JSON document which should be the subject of querying. | |
| 183 | + * @return the result of the evaluation | |
| 184 | + * @throws JSONPointerException if an error occurs during evaluation | |
| 185 | + */ | |
| 186 | + public Object queryFrom(Object document) throws JSONPointerException { | |
| 187 | + if (this.refTokens.isEmpty()) { | |
| 188 | + return document; | |
| 189 | + } | |
| 190 | + Object current = document; | |
| 191 | + for (String token : this.refTokens) { | |
| 192 | + if (current instanceof JSONObject) { | |
| 193 | + current = ((JSONObject) current).opt(unescape(token)); | |
| 194 | + } else if (current instanceof JSONArray) { | |
| 195 | + current = readByIndexToken(current, token); | |
| 196 | + } else { | |
| 197 | + throw new JSONPointerException(format( | |
| 198 | + "value [%s] is not an array or object therefore its key %s cannot be resolved", current, | |
| 199 | + token)); | |
| 200 | + } | |
| 201 | + } | |
| 202 | + return current; | |
| 203 | + } | |
| 204 | + | |
| 205 | + /** | |
| 206 | + * Matches a JSONArray element by ordinal position | |
| 207 | + * @param current the JSONArray to be evaluated | |
| 208 | + * @param indexToken the array index in string form | |
| 209 | + * @return the matched object. If no matching item is found a | |
| 210 | + * @throws JSONPointerException is thrown if the index is out of bounds | |
| 211 | + */ | |
| 212 | + private Object readByIndexToken(Object current, String indexToken) throws JSONPointerException { | |
| 213 | + try { | |
| 214 | + int index = Integer.parseInt(indexToken); | |
| 215 | + JSONArray currentArr = (JSONArray) current; | |
| 216 | + if (index >= currentArr.length()) { | |
| 217 | + throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index, | |
| 218 | + currentArr.length())); | |
| 219 | + } | |
| 220 | + try { | |
| 221 | + return currentArr.get(index); | |
| 222 | + } catch (JSONException e) { | |
| 223 | + throw new JSONPointerException("Error reading value at index position " + index, e); | |
| 224 | + } | |
| 225 | + } catch (NumberFormatException e) { | |
| 226 | + throw new JSONPointerException(format("%s is not an array index", indexToken), e); | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + /** | |
| 231 | + * Returns a string representing the JSONPointer path value using string | |
| 232 | + * representation | |
| 233 | + */ | |
| 234 | + @Override | |
| 235 | + public String toString() { | |
| 236 | + StringBuilder rval = new StringBuilder(""); | |
| 237 | + for (String token: this.refTokens) { | |
| 238 | + rval.append('/').append(escape(token)); | |
| 239 | + } | |
| 240 | + return rval.toString(); | |
| 241 | + } | |
| 242 | + | |
| 243 | + /** | |
| 244 | + * Escapes path segment values to an unambiguous form. | |
| 245 | + * The escape char to be inserted is '~'. The chars to be escaped | |
| 246 | + * are ~, which maps to ~0, and /, which maps to ~1. Backslashes | |
| 247 | + * and double quote chars are also escaped. | |
| 248 | + * @param token the JSONPointer segment value to be escaped | |
| 249 | + * @return the escaped value for the token | |
| 250 | + */ | |
| 251 | + private String escape(String token) { | |
| 252 | + return token.replace("~", "~0") | |
| 253 | + .replace("/", "~1") | |
| 254 | + .replace("\\", "\\\\") | |
| 255 | + .replace("\"", "\\\""); | |
| 256 | + } | |
| 257 | + | |
| 258 | + /** | |
| 259 | + * Returns a string representing the JSONPointer path value using URI | |
| 260 | + * fragment identifier representation | |
| 261 | + */ | |
| 262 | + public String toURIFragment() { | |
| 263 | + try { | |
| 264 | + StringBuilder rval = new StringBuilder("#"); | |
| 265 | + for (String token : this.refTokens) { | |
| 266 | + rval.append('/').append(URLEncoder.encode(token, ENCODING)); | |
| 267 | + } | |
| 268 | + return rval.toString(); | |
| 269 | + } catch (UnsupportedEncodingException e) { | |
| 270 | + throw new RuntimeException(e); | |
| 271 | + } | |
| 272 | + } | |
| 273 | + | |
| 274 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONPointerException.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * The JSONPointerException is thrown by {@link JSONPointer} if an error occurs | |
| 29 | + * during evaluating a pointer. | |
| 30 | + * | |
| 31 | + * @author JSON.org | |
| 32 | + * @version 2016-05-13 | |
| 33 | + */ | |
| 34 | +public class JSONPointerException extends JSONException { | |
| 35 | + private static final long serialVersionUID = 8872944667561856751L; | |
| 36 | + | |
| 37 | + public JSONPointerException(String message) { | |
| 38 | + super(message); | |
| 39 | + } | |
| 40 | + | |
| 41 | + public JSONPointerException(String message, Throwable cause) { | |
| 42 | + super(message, cause); | |
| 43 | + } | |
| 44 | + | |
| 45 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONString.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | +/** | |
| 3 | + * The <code>JSONString</code> interface allows a <code>toJSONString()</code> | |
| 4 | + * method so that a class can change the behavior of | |
| 5 | + * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, | |
| 6 | + * and <code>JSONWriter.value(</code>Object<code>)</code>. The | |
| 7 | + * <code>toJSONString</code> method will be used instead of the default behavior | |
| 8 | + * of using the Object's <code>toString()</code> method and quoting the result. | |
| 9 | + */ | |
| 10 | +public interface JSONString { | |
| 11 | + /** | |
| 12 | + * The <code>toJSONString</code> method allows a class to produce its own JSON | |
| 13 | + * serialization. | |
| 14 | + * | |
| 15 | + * @return A strictly syntactically correct JSON text. | |
| 16 | + */ | |
| 17 | + public String toJSONString(); | |
| 18 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONStringer.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2006 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +import java.io.StringWriter; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * JSONStringer provides a quick and convenient way of producing JSON text. | |
| 31 | + * The texts produced strictly conform to JSON syntax rules. No whitespace is | |
| 32 | + * added, so the results are ready for transmission or storage. Each instance of | |
| 33 | + * JSONStringer can produce one JSON text. | |
| 34 | + * <p> | |
| 35 | + * A JSONStringer instance provides a <code>value</code> method for appending | |
| 36 | + * values to the | |
| 37 | + * text, and a <code>key</code> | |
| 38 | + * method for adding keys before values in objects. There are <code>array</code> | |
| 39 | + * and <code>endArray</code> methods that make and bound array values, and | |
| 40 | + * <code>object</code> and <code>endObject</code> methods which make and bound | |
| 41 | + * object values. All of these methods return the JSONWriter instance, | |
| 42 | + * permitting cascade style. For example, <pre> | |
| 43 | + * myString = new JSONStringer() | |
| 44 | + * .object() | |
| 45 | + * .key("JSON") | |
| 46 | + * .value("Hello, World!") | |
| 47 | + * .endObject() | |
| 48 | + * .toString();</pre> which produces the string <pre> | |
| 49 | + * {"JSON":"Hello, World!"}</pre> | |
| 50 | + * <p> | |
| 51 | + * The first method called must be <code>array</code> or <code>object</code>. | |
| 52 | + * There are no methods for adding commas or colons. JSONStringer adds them for | |
| 53 | + * you. Objects and arrays can be nested up to 20 levels deep. | |
| 54 | + * <p> | |
| 55 | + * This can sometimes be easier than using a JSONObject to build a string. | |
| 56 | + * @author JSON.org | |
| 57 | + * @version 2015-12-09 | |
| 58 | + */ | |
| 59 | +public class JSONStringer extends JSONWriter { | |
| 60 | + /** | |
| 61 | + * Make a fresh JSONStringer. It can be used to build one JSON text. | |
| 62 | + */ | |
| 63 | + public JSONStringer() { | |
| 64 | + super(new StringWriter()); | |
| 65 | + } | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Return the JSON text. This method is used to obtain the product of the | |
| 69 | + * JSONStringer instance. It will return <code>null</code> if there was a | |
| 70 | + * problem in the construction of the JSON text (such as the calls to | |
| 71 | + * <code>array</code> were not properly balanced with calls to | |
| 72 | + * <code>endArray</code>). | |
| 73 | + * @return The JSON text. | |
| 74 | + */ | |
| 75 | + @Override | |
| 76 | + public String toString() { | |
| 77 | + return this.mode == 'd' ? this.writer.toString() : null; | |
| 78 | + } | |
| 79 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONTokener.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +import java.io.*; | |
| 4 | + | |
| 5 | +/* | |
| 6 | +Copyright (c) 2002 JSON.org | |
| 7 | + | |
| 8 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 9 | +of this software and associated documentation files (the "Software"), to deal | |
| 10 | +in the Software without restriction, including without limitation the rights | |
| 11 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 12 | +copies of the Software, and to permit persons to whom the Software is | |
| 13 | +furnished to do so, subject to the following conditions: | |
| 14 | + | |
| 15 | +The above copyright notice and this permission notice shall be included in all | |
| 16 | +copies or substantial portions of the Software. | |
| 17 | + | |
| 18 | +The Software shall be used for Good, not Evil. | |
| 19 | + | |
| 20 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 23 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 25 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 26 | +SOFTWARE. | |
| 27 | + */ | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * A JSONTokener takes a source string and extracts characters and tokens from | |
| 31 | + * it. It is used by the JSONObject and JSONArray constructors to parse | |
| 32 | + * JSON source strings. | |
| 33 | + * @author JSON.org | |
| 34 | + * @version 2014-05-03 | |
| 35 | + */ | |
| 36 | +public class JSONTokener { | |
| 37 | + /** current read character position on the current line. */ | |
| 38 | + private long character; | |
| 39 | + /** flag to indicate if the end of the input has been found. */ | |
| 40 | + private boolean eof; | |
| 41 | + /** current read index of the input. */ | |
| 42 | + private long index; | |
| 43 | + /** current line of the input. */ | |
| 44 | + private long line; | |
| 45 | + /** previous character read from the input. */ | |
| 46 | + private char previous; | |
| 47 | + /** Reader for the input. */ | |
| 48 | + private final Reader reader; | |
| 49 | + /** flag to indicate that a previous character was requested. */ | |
| 50 | + private boolean usePrevious; | |
| 51 | + /** the number of characters read in the previous line. */ | |
| 52 | + private long characterPreviousLine; | |
| 53 | + | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Construct a JSONTokener from a Reader. The caller must close the Reader. | |
| 57 | + * | |
| 58 | + * @param reader A reader. | |
| 59 | + */ | |
| 60 | + public JSONTokener(Reader reader) { | |
| 61 | + this.reader = reader.markSupported() | |
| 62 | + ? reader | |
| 63 | + : new BufferedReader(reader); | |
| 64 | + this.eof = false; | |
| 65 | + this.usePrevious = false; | |
| 66 | + this.previous = 0; | |
| 67 | + this.index = 0; | |
| 68 | + this.character = 1; | |
| 69 | + this.characterPreviousLine = 0; | |
| 70 | + this.line = 1; | |
| 71 | + } | |
| 72 | + | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * Construct a JSONTokener from an InputStream. The caller must close the input stream. | |
| 76 | + * @param inputStream The source. | |
| 77 | + */ | |
| 78 | + public JSONTokener(InputStream inputStream) { | |
| 79 | + this(new InputStreamReader(inputStream)); | |
| 80 | + } | |
| 81 | + | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Construct a JSONTokener from a string. | |
| 85 | + * | |
| 86 | + * @param s A source string. | |
| 87 | + */ | |
| 88 | + public JSONTokener(String s) { | |
| 89 | + this(new StringReader(s)); | |
| 90 | + } | |
| 91 | + | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * Back up one character. This provides a sort of lookahead capability, | |
| 95 | + * so that you can test for a digit or letter before attempting to parse | |
| 96 | + * the next number or identifier. | |
| 97 | + * @throws JSONException Thrown if trying to step back more than 1 step | |
| 98 | + * or if already at the start of the string | |
| 99 | + */ | |
| 100 | + public void back() throws JSONException { | |
| 101 | + if (this.usePrevious || this.index <= 0) { | |
| 102 | + throw new JSONException("Stepping back two steps is not supported"); | |
| 103 | + } | |
| 104 | + this.decrementIndexes(); | |
| 105 | + this.usePrevious = true; | |
| 106 | + this.eof = false; | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Decrements the indexes for the {@link #back()} method based on the previous character read. | |
| 111 | + */ | |
| 112 | + private void decrementIndexes() { | |
| 113 | + this.index--; | |
| 114 | + if(this.previous=='\r' || this.previous == '\n') { | |
| 115 | + this.line--; | |
| 116 | + this.character=this.characterPreviousLine ; | |
| 117 | + } else if(this.character > 0){ | |
| 118 | + this.character--; | |
| 119 | + } | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * Get the hex value of a character (base16). | |
| 124 | + * @param c A character between '0' and '9' or between 'A' and 'F' or | |
| 125 | + * between 'a' and 'f'. | |
| 126 | + * @return An int between 0 and 15, or -1 if c was not a hex digit. | |
| 127 | + */ | |
| 128 | + public static int dehexchar(char c) { | |
| 129 | + if (c >= '0' && c <= '9') { | |
| 130 | + return c - '0'; | |
| 131 | + } | |
| 132 | + if (c >= 'A' && c <= 'F') { | |
| 133 | + return c - ('A' - 10); | |
| 134 | + } | |
| 135 | + if (c >= 'a' && c <= 'f') { | |
| 136 | + return c - ('a' - 10); | |
| 137 | + } | |
| 138 | + return -1; | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Checks if the end of the input has been reached. | |
| 143 | + * | |
| 144 | + * @return true if at the end of the file and we didn't step back | |
| 145 | + */ | |
| 146 | + public boolean end() { | |
| 147 | + return this.eof && !this.usePrevious; | |
| 148 | + } | |
| 149 | + | |
| 150 | + | |
| 151 | + /** | |
| 152 | + * Determine if the source string still contains characters that next() | |
| 153 | + * can consume. | |
| 154 | + * @return true if not yet at the end of the source. | |
| 155 | + * @throws JSONException thrown if there is an error stepping forward | |
| 156 | + * or backward while checking for more data. | |
| 157 | + */ | |
| 158 | + public boolean more() throws JSONException { | |
| 159 | + if(this.usePrevious) { | |
| 160 | + return true; | |
| 161 | + } | |
| 162 | + try { | |
| 163 | + this.reader.mark(1); | |
| 164 | + } catch (IOException e) { | |
| 165 | + throw new JSONException("Unable to preserve stream position", e); | |
| 166 | + } | |
| 167 | + try { | |
| 168 | + // -1 is EOF, but next() can not consume the null character '\0' | |
| 169 | + if(this.reader.read() <= 0) { | |
| 170 | + this.eof = true; | |
| 171 | + return false; | |
| 172 | + } | |
| 173 | + this.reader.reset(); | |
| 174 | + } catch (IOException e) { | |
| 175 | + throw new JSONException("Unable to read the next character from the stream", e); | |
| 176 | + } | |
| 177 | + return true; | |
| 178 | + } | |
| 179 | + | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Get the next character in the source string. | |
| 183 | + * | |
| 184 | + * @return The next character, or 0 if past the end of the source string. | |
| 185 | + * @throws JSONException Thrown if there is an error reading the source string. | |
| 186 | + */ | |
| 187 | + public char next() throws JSONException { | |
| 188 | + int c; | |
| 189 | + if (this.usePrevious) { | |
| 190 | + this.usePrevious = false; | |
| 191 | + c = this.previous; | |
| 192 | + } else { | |
| 193 | + try { | |
| 194 | + c = this.reader.read(); | |
| 195 | + } catch (IOException exception) { | |
| 196 | + throw new JSONException(exception); | |
| 197 | + } | |
| 198 | + } | |
| 199 | + if (c <= 0) { // End of stream | |
| 200 | + this.eof = true; | |
| 201 | + return 0; | |
| 202 | + } | |
| 203 | + this.incrementIndexes(c); | |
| 204 | + this.previous = (char) c; | |
| 205 | + return this.previous; | |
| 206 | + } | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Increments the internal indexes according to the previous character | |
| 210 | + * read and the character passed as the current character. | |
| 211 | + * @param c the current character read. | |
| 212 | + */ | |
| 213 | + private void incrementIndexes(int c) { | |
| 214 | + if(c > 0) { | |
| 215 | + this.index++; | |
| 216 | + if(c=='\r') { | |
| 217 | + this.line++; | |
| 218 | + this.characterPreviousLine = this.character; | |
| 219 | + this.character=0; | |
| 220 | + }else if (c=='\n') { | |
| 221 | + if(this.previous != '\r') { | |
| 222 | + this.line++; | |
| 223 | + this.characterPreviousLine = this.character; | |
| 224 | + } | |
| 225 | + this.character=0; | |
| 226 | + } else { | |
| 227 | + this.character++; | |
| 228 | + } | |
| 229 | + } | |
| 230 | + } | |
| 231 | + | |
| 232 | + /** | |
| 233 | + * Consume the next character, and check that it matches a specified | |
| 234 | + * character. | |
| 235 | + * @param c The character to match. | |
| 236 | + * @return The character. | |
| 237 | + * @throws JSONException if the character does not match. | |
| 238 | + */ | |
| 239 | + public char next(char c) throws JSONException { | |
| 240 | + char n = this.next(); | |
| 241 | + if (n != c) { | |
| 242 | + if(n > 0) { | |
| 243 | + throw this.syntaxError("Expected '" + c + "' and instead saw '" + | |
| 244 | + n + "'"); | |
| 245 | + } | |
| 246 | + throw this.syntaxError("Expected '" + c + "' and instead saw ''"); | |
| 247 | + } | |
| 248 | + return n; | |
| 249 | + } | |
| 250 | + | |
| 251 | + | |
| 252 | + /** | |
| 253 | + * Get the next n characters. | |
| 254 | + * | |
| 255 | + * @param n The number of characters to take. | |
| 256 | + * @return A string of n characters. | |
| 257 | + * @throws JSONException | |
| 258 | + * Substring bounds error if there are not | |
| 259 | + * n characters remaining in the source string. | |
| 260 | + */ | |
| 261 | + public String next(int n) throws JSONException { | |
| 262 | + if (n == 0) { | |
| 263 | + return ""; | |
| 264 | + } | |
| 265 | + | |
| 266 | + char[] chars = new char[n]; | |
| 267 | + int pos = 0; | |
| 268 | + | |
| 269 | + while (pos < n) { | |
| 270 | + chars[pos] = this.next(); | |
| 271 | + if (this.end()) { | |
| 272 | + throw this.syntaxError("Substring bounds error"); | |
| 273 | + } | |
| 274 | + pos += 1; | |
| 275 | + } | |
| 276 | + return new String(chars); | |
| 277 | + } | |
| 278 | + | |
| 279 | + | |
| 280 | + /** | |
| 281 | + * Get the next char in the string, skipping whitespace. | |
| 282 | + * @throws JSONException Thrown if there is an error reading the source string. | |
| 283 | + * @return A character, or 0 if there are no more characters. | |
| 284 | + */ | |
| 285 | + public char nextClean() throws JSONException { | |
| 286 | + for (;;) { | |
| 287 | + char c = this.next(); | |
| 288 | + if (c == 0 || c > ' ') { | |
| 289 | + return c; | |
| 290 | + } | |
| 291 | + } | |
| 292 | + } | |
| 293 | + | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * Return the characters up to the next close quote character. | |
| 297 | + * Backslash processing is done. The formal JSON format does not | |
| 298 | + * allow strings in single quotes, but an implementation is allowed to | |
| 299 | + * accept them. | |
| 300 | + * @param quote The quoting character, either | |
| 301 | + * <code>"</code> <small>(double quote)</small> or | |
| 302 | + * <code>'</code> <small>(single quote)</small>. | |
| 303 | + * @return A String. | |
| 304 | + * @throws JSONException Unterminated string. | |
| 305 | + */ | |
| 306 | + public String nextString(char quote) throws JSONException { | |
| 307 | + char c; | |
| 308 | + StringBuilder sb = new StringBuilder(); | |
| 309 | + for (;;) { | |
| 310 | + c = this.next(); | |
| 311 | + switch (c) { | |
| 312 | + case 0: | |
| 313 | + case '\n': | |
| 314 | + case '\r': | |
| 315 | + throw this.syntaxError("Unterminated string"); | |
| 316 | + case '\\': | |
| 317 | + c = this.next(); | |
| 318 | + switch (c) { | |
| 319 | + case 'b': | |
| 320 | + sb.append('\b'); | |
| 321 | + break; | |
| 322 | + case 't': | |
| 323 | + sb.append('\t'); | |
| 324 | + break; | |
| 325 | + case 'n': | |
| 326 | + sb.append('\n'); | |
| 327 | + break; | |
| 328 | + case 'f': | |
| 329 | + sb.append('\f'); | |
| 330 | + break; | |
| 331 | + case 'r': | |
| 332 | + sb.append('\r'); | |
| 333 | + break; | |
| 334 | + case 'u': | |
| 335 | + try { | |
| 336 | + sb.append((char)Integer.parseInt(this.next(4), 16)); | |
| 337 | + } catch (NumberFormatException e) { | |
| 338 | + throw this.syntaxError("Illegal escape.", e); | |
| 339 | + } | |
| 340 | + break; | |
| 341 | + case '"': | |
| 342 | + case '\'': | |
| 343 | + case '\\': | |
| 344 | + case '/': | |
| 345 | + sb.append(c); | |
| 346 | + break; | |
| 347 | + default: | |
| 348 | + throw this.syntaxError("Illegal escape."); | |
| 349 | + } | |
| 350 | + break; | |
| 351 | + default: | |
| 352 | + if (c == quote) { | |
| 353 | + return sb.toString(); | |
| 354 | + } | |
| 355 | + sb.append(c); | |
| 356 | + } | |
| 357 | + } | |
| 358 | + } | |
| 359 | + | |
| 360 | + | |
| 361 | + /** | |
| 362 | + * Get the text up but not including the specified character or the | |
| 363 | + * end of line, whichever comes first. | |
| 364 | + * @param delimiter A delimiter character. | |
| 365 | + * @return A string. | |
| 366 | + * @throws JSONException Thrown if there is an error while searching | |
| 367 | + * for the delimiter | |
| 368 | + */ | |
| 369 | + public String nextTo(char delimiter) throws JSONException { | |
| 370 | + StringBuilder sb = new StringBuilder(); | |
| 371 | + for (;;) { | |
| 372 | + char c = this.next(); | |
| 373 | + if (c == delimiter || c == 0 || c == '\n' || c == '\r') { | |
| 374 | + if (c != 0) { | |
| 375 | + this.back(); | |
| 376 | + } | |
| 377 | + return sb.toString().trim(); | |
| 378 | + } | |
| 379 | + sb.append(c); | |
| 380 | + } | |
| 381 | + } | |
| 382 | + | |
| 383 | + | |
| 384 | + /** | |
| 385 | + * Get the text up but not including one of the specified delimiter | |
| 386 | + * characters or the end of line, whichever comes first. | |
| 387 | + * @param delimiters A set of delimiter characters. | |
| 388 | + * @return A string, trimmed. | |
| 389 | + * @throws JSONException Thrown if there is an error while searching | |
| 390 | + * for the delimiter | |
| 391 | + */ | |
| 392 | + public String nextTo(String delimiters) throws JSONException { | |
| 393 | + char c; | |
| 394 | + StringBuilder sb = new StringBuilder(); | |
| 395 | + for (;;) { | |
| 396 | + c = this.next(); | |
| 397 | + if (delimiters.indexOf(c) >= 0 || c == 0 || | |
| 398 | + c == '\n' || c == '\r') { | |
| 399 | + if (c != 0) { | |
| 400 | + this.back(); | |
| 401 | + } | |
| 402 | + return sb.toString().trim(); | |
| 403 | + } | |
| 404 | + sb.append(c); | |
| 405 | + } | |
| 406 | + } | |
| 407 | + | |
| 408 | + | |
| 409 | + /** | |
| 410 | + * Get the next value. The value can be a Boolean, Double, Integer, | |
| 411 | + * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. | |
| 412 | + * @throws JSONException If syntax error. | |
| 413 | + * | |
| 414 | + * @return An object. | |
| 415 | + */ | |
| 416 | + public Object nextValue() throws JSONException { | |
| 417 | + char c = this.nextClean(); | |
| 418 | + String string; | |
| 419 | + | |
| 420 | + switch (c) { | |
| 421 | + case '"': | |
| 422 | + case '\'': | |
| 423 | + return this.nextString(c); | |
| 424 | + case '{': | |
| 425 | + this.back(); | |
| 426 | + return new JSONObject(this); | |
| 427 | + case '[': | |
| 428 | + this.back(); | |
| 429 | + return new JSONArray(this); | |
| 430 | + } | |
| 431 | + | |
| 432 | + /* | |
| 433 | + * Handle unquoted text. This could be the values true, false, or | |
| 434 | + * null, or it can be a number. An implementation (such as this one) | |
| 435 | + * is allowed to also accept non-standard forms. | |
| 436 | + * | |
| 437 | + * Accumulate characters until we reach the end of the text or a | |
| 438 | + * formatting character. | |
| 439 | + */ | |
| 440 | + | |
| 441 | + StringBuilder sb = new StringBuilder(); | |
| 442 | + while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { | |
| 443 | + sb.append(c); | |
| 444 | + c = this.next(); | |
| 445 | + } | |
| 446 | + this.back(); | |
| 447 | + | |
| 448 | + string = sb.toString().trim(); | |
| 449 | + if ("".equals(string)) { | |
| 450 | + throw this.syntaxError("Missing value"); | |
| 451 | + } | |
| 452 | + return JSONObject.stringToValue(string); | |
| 453 | + } | |
| 454 | + | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * Skip characters until the next character is the requested character. | |
| 458 | + * If the requested character is not found, no characters are skipped. | |
| 459 | + * @param to A character to skip to. | |
| 460 | + * @return The requested character, or zero if the requested character | |
| 461 | + * is not found. | |
| 462 | + * @throws JSONException Thrown if there is an error while searching | |
| 463 | + * for the to character | |
| 464 | + */ | |
| 465 | + public char skipTo(char to) throws JSONException { | |
| 466 | + char c; | |
| 467 | + try { | |
| 468 | + long startIndex = this.index; | |
| 469 | + long startCharacter = this.character; | |
| 470 | + long startLine = this.line; | |
| 471 | + this.reader.mark(1000000); | |
| 472 | + do { | |
| 473 | + c = this.next(); | |
| 474 | + if (c == 0) { | |
| 475 | + // in some readers, reset() may throw an exception if | |
| 476 | + // the remaining portion of the input is greater than | |
| 477 | + // the mark size (1,000,000 above). | |
| 478 | + this.reader.reset(); | |
| 479 | + this.index = startIndex; | |
| 480 | + this.character = startCharacter; | |
| 481 | + this.line = startLine; | |
| 482 | + return 0; | |
| 483 | + } | |
| 484 | + } while (c != to); | |
| 485 | + this.reader.mark(1); | |
| 486 | + } catch (IOException exception) { | |
| 487 | + throw new JSONException(exception); | |
| 488 | + } | |
| 489 | + this.back(); | |
| 490 | + return c; | |
| 491 | + } | |
| 492 | + | |
| 493 | + /** | |
| 494 | + * Make a JSONException to signal a syntax error. | |
| 495 | + * | |
| 496 | + * @param message The error message. | |
| 497 | + * @return A JSONException object, suitable for throwing | |
| 498 | + */ | |
| 499 | + public JSONException syntaxError(String message) { | |
| 500 | + return new JSONException(message + this.toString()); | |
| 501 | + } | |
| 502 | + | |
| 503 | + /** | |
| 504 | + * Make a JSONException to signal a syntax error. | |
| 505 | + * | |
| 506 | + * @param message The error message. | |
| 507 | + * @param causedBy The throwable that caused the error. | |
| 508 | + * @return A JSONException object, suitable for throwing | |
| 509 | + */ | |
| 510 | + public JSONException syntaxError(String message, Throwable causedBy) { | |
| 511 | + return new JSONException(message + this.toString(), causedBy); | |
| 512 | + } | |
| 513 | + | |
| 514 | + /** | |
| 515 | + * Make a printable string of this JSONTokener. | |
| 516 | + * | |
| 517 | + * @return " at {index} [character {character} line {line}]" | |
| 518 | + */ | |
| 519 | + @Override | |
| 520 | + public String toString() { | |
| 521 | + return " at " + this.index + " [character " + this.character + " line " + | |
| 522 | + this.line + "]"; | |
| 523 | + } | |
| 524 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/JSONWriter.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +import java.io.IOException; | |
| 4 | +import java.math.BigDecimal; | |
| 5 | +import java.util.Collection; | |
| 6 | +import java.util.Map; | |
| 7 | + | |
| 8 | +/* | |
| 9 | +Copyright (c) 2006 JSON.org | |
| 10 | + | |
| 11 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 12 | +of this software and associated documentation files (the "Software"), to deal | |
| 13 | +in the Software without restriction, including without limitation the rights | |
| 14 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 15 | +copies of the Software, and to permit persons to whom the Software is | |
| 16 | +furnished to do so, subject to the following conditions: | |
| 17 | + | |
| 18 | +The above copyright notice and this permission notice shall be included in all | |
| 19 | +copies or substantial portions of the Software. | |
| 20 | + | |
| 21 | +The Software shall be used for Good, not Evil. | |
| 22 | + | |
| 23 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 24 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 25 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 26 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 27 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 28 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 29 | +SOFTWARE. | |
| 30 | +*/ | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * JSONWriter provides a quick and convenient way of producing JSON text. | |
| 34 | + * The texts produced strictly conform to JSON syntax rules. No whitespace is | |
| 35 | + * added, so the results are ready for transmission or storage. Each instance of | |
| 36 | + * JSONWriter can produce one JSON text. | |
| 37 | + * <p> | |
| 38 | + * A JSONWriter instance provides a <code>value</code> method for appending | |
| 39 | + * values to the | |
| 40 | + * text, and a <code>key</code> | |
| 41 | + * method for adding keys before values in objects. There are <code>array</code> | |
| 42 | + * and <code>endArray</code> methods that make and bound array values, and | |
| 43 | + * <code>object</code> and <code>endObject</code> methods which make and bound | |
| 44 | + * object values. All of these methods return the JSONWriter instance, | |
| 45 | + * permitting a cascade style. For example, <pre> | |
| 46 | + * new JSONWriter(myWriter) | |
| 47 | + * .object() | |
| 48 | + * .key("JSON") | |
| 49 | + * .value("Hello, World!") | |
| 50 | + * .endObject();</pre> which writes <pre> | |
| 51 | + * {"JSON":"Hello, World!"}</pre> | |
| 52 | + * <p> | |
| 53 | + * The first method called must be <code>array</code> or <code>object</code>. | |
| 54 | + * There are no methods for adding commas or colons. JSONWriter adds them for | |
| 55 | + * you. Objects and arrays can be nested up to 200 levels deep. | |
| 56 | + * <p> | |
| 57 | + * This can sometimes be easier than using a JSONObject to build a string. | |
| 58 | + * @author JSON.org | |
| 59 | + * @version 2016-08-08 | |
| 60 | + */ | |
| 61 | +public class JSONWriter { | |
| 62 | + private static final int maxdepth = 200; | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * The comma flag determines if a comma should be output before the next | |
| 66 | + * value. | |
| 67 | + */ | |
| 68 | + private boolean comma; | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * The current mode. Values: | |
| 72 | + * 'a' (array), | |
| 73 | + * 'd' (done), | |
| 74 | + * 'i' (initial), | |
| 75 | + * 'k' (key), | |
| 76 | + * 'o' (object). | |
| 77 | + */ | |
| 78 | + protected char mode; | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * The object/array stack. | |
| 82 | + */ | |
| 83 | + private final JSONObject stack[]; | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * The stack top index. A value of 0 indicates that the stack is empty. | |
| 87 | + */ | |
| 88 | + private int top; | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * The writer that will receive the output. | |
| 92 | + */ | |
| 93 | + protected Appendable writer; | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Make a fresh JSONWriter. It can be used to build one JSON text. | |
| 97 | + */ | |
| 98 | + public JSONWriter(Appendable w) { | |
| 99 | + this.comma = false; | |
| 100 | + this.mode = 'i'; | |
| 101 | + this.stack = new JSONObject[maxdepth]; | |
| 102 | + this.top = 0; | |
| 103 | + this.writer = w; | |
| 104 | + } | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * Append a value. | |
| 108 | + * @param string A string value. | |
| 109 | + * @return this | |
| 110 | + * @throws JSONException If the value is out of sequence. | |
| 111 | + */ | |
| 112 | + private JSONWriter append(String string) throws JSONException { | |
| 113 | + if (string == null) { | |
| 114 | + throw new JSONException("Null pointer"); | |
| 115 | + } | |
| 116 | + if (this.mode == 'o' || this.mode == 'a') { | |
| 117 | + try { | |
| 118 | + if (this.comma && this.mode == 'a') { | |
| 119 | + this.writer.append(','); | |
| 120 | + } | |
| 121 | + this.writer.append(string); | |
| 122 | + } catch (IOException e) { | |
| 123 | + // Android as of API 25 does not support this exception constructor | |
| 124 | + // however we won't worry about it. If an exception is happening here | |
| 125 | + // it will just throw a "Method not found" exception instead. | |
| 126 | + throw new JSONException(e); | |
| 127 | + } | |
| 128 | + if (this.mode == 'o') { | |
| 129 | + this.mode = 'k'; | |
| 130 | + } | |
| 131 | + this.comma = true; | |
| 132 | + return this; | |
| 133 | + } | |
| 134 | + throw new JSONException("Value out of sequence."); | |
| 135 | + } | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * Begin appending a new array. All values until the balancing | |
| 139 | + * <code>endArray</code> will be appended to this array. The | |
| 140 | + * <code>endArray</code> method must be called to mark the array's end. | |
| 141 | + * @return this | |
| 142 | + * @throws JSONException If the nesting is too deep, or if the object is | |
| 143 | + * started in the wrong place (for example as a key or after the end of the | |
| 144 | + * outermost array or object). | |
| 145 | + */ | |
| 146 | + public JSONWriter array() throws JSONException { | |
| 147 | + if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { | |
| 148 | + this.push(null); | |
| 149 | + this.append("["); | |
| 150 | + this.comma = false; | |
| 151 | + return this; | |
| 152 | + } | |
| 153 | + throw new JSONException("Misplaced array."); | |
| 154 | + } | |
| 155 | + | |
| 156 | + /** | |
| 157 | + * End something. | |
| 158 | + * @param m Mode | |
| 159 | + * @param c Closing character | |
| 160 | + * @return this | |
| 161 | + * @throws JSONException If unbalanced. | |
| 162 | + */ | |
| 163 | + private JSONWriter end(char m, char c) throws JSONException { | |
| 164 | + if (this.mode != m) { | |
| 165 | + throw new JSONException(m == 'a' | |
| 166 | + ? "Misplaced endArray." | |
| 167 | + : "Misplaced endObject."); | |
| 168 | + } | |
| 169 | + this.pop(m); | |
| 170 | + try { | |
| 171 | + this.writer.append(c); | |
| 172 | + } catch (IOException e) { | |
| 173 | + // Android as of API 25 does not support this exception constructor | |
| 174 | + // however we won't worry about it. If an exception is happening here | |
| 175 | + // it will just throw a "Method not found" exception instead. | |
| 176 | + throw new JSONException(e); | |
| 177 | + } | |
| 178 | + this.comma = true; | |
| 179 | + return this; | |
| 180 | + } | |
| 181 | + | |
| 182 | + /** | |
| 183 | + * End an array. This method most be called to balance calls to | |
| 184 | + * <code>array</code>. | |
| 185 | + * @return this | |
| 186 | + * @throws JSONException If incorrectly nested. | |
| 187 | + */ | |
| 188 | + public JSONWriter endArray() throws JSONException { | |
| 189 | + return this.end('a', ']'); | |
| 190 | + } | |
| 191 | + | |
| 192 | + /** | |
| 193 | + * End an object. This method most be called to balance calls to | |
| 194 | + * <code>object</code>. | |
| 195 | + * @return this | |
| 196 | + * @throws JSONException If incorrectly nested. | |
| 197 | + */ | |
| 198 | + public JSONWriter endObject() throws JSONException { | |
| 199 | + return this.end('k', '}'); | |
| 200 | + } | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * Append a key. The key will be associated with the next value. In an | |
| 204 | + * object, every value must be preceded by a key. | |
| 205 | + * @param string A key string. | |
| 206 | + * @return this | |
| 207 | + * @throws JSONException If the key is out of place. For example, keys | |
| 208 | + * do not belong in arrays or if the key is null. | |
| 209 | + */ | |
| 210 | + public JSONWriter key(String string) throws JSONException { | |
| 211 | + if (string == null) { | |
| 212 | + throw new JSONException("Null key."); | |
| 213 | + } | |
| 214 | + if (this.mode == 'k') { | |
| 215 | + try { | |
| 216 | + JSONObject topObject = this.stack[this.top - 1]; | |
| 217 | + // don't use the built in putOnce method to maintain Android support | |
| 218 | + if(topObject.has(string)) { | |
| 219 | + throw new JSONException("Duplicate key \"" + string + "\""); | |
| 220 | + } | |
| 221 | + topObject.put(string, true); | |
| 222 | + if (this.comma) { | |
| 223 | + this.writer.append(','); | |
| 224 | + } | |
| 225 | + this.writer.append(JSONObject.quote(string)); | |
| 226 | + this.writer.append(':'); | |
| 227 | + this.comma = false; | |
| 228 | + this.mode = 'o'; | |
| 229 | + return this; | |
| 230 | + } catch (IOException e) { | |
| 231 | + // Android as of API 25 does not support this exception constructor | |
| 232 | + // however we won't worry about it. If an exception is happening here | |
| 233 | + // it will just throw a "Method not found" exception instead. | |
| 234 | + throw new JSONException(e); | |
| 235 | + } | |
| 236 | + } | |
| 237 | + throw new JSONException("Misplaced key."); | |
| 238 | + } | |
| 239 | + | |
| 240 | + | |
| 241 | + /** | |
| 242 | + * Begin appending a new object. All keys and values until the balancing | |
| 243 | + * <code>endObject</code> will be appended to this object. The | |
| 244 | + * <code>endObject</code> method must be called to mark the object's end. | |
| 245 | + * @return this | |
| 246 | + * @throws JSONException If the nesting is too deep, or if the object is | |
| 247 | + * started in the wrong place (for example as a key or after the end of the | |
| 248 | + * outermost array or object). | |
| 249 | + */ | |
| 250 | + public JSONWriter object() throws JSONException { | |
| 251 | + if (this.mode == 'i') { | |
| 252 | + this.mode = 'o'; | |
| 253 | + } | |
| 254 | + if (this.mode == 'o' || this.mode == 'a') { | |
| 255 | + this.append("{"); | |
| 256 | + this.push(new JSONObject()); | |
| 257 | + this.comma = false; | |
| 258 | + return this; | |
| 259 | + } | |
| 260 | + throw new JSONException("Misplaced object."); | |
| 261 | + | |
| 262 | + } | |
| 263 | + | |
| 264 | + | |
| 265 | + /** | |
| 266 | + * Pop an array or object scope. | |
| 267 | + * @param c The scope to close. | |
| 268 | + * @throws JSONException If nesting is wrong. | |
| 269 | + */ | |
| 270 | + private void pop(char c) throws JSONException { | |
| 271 | + if (this.top <= 0) { | |
| 272 | + throw new JSONException("Nesting error."); | |
| 273 | + } | |
| 274 | + char m = this.stack[this.top - 1] == null ? 'a' : 'k'; | |
| 275 | + if (m != c) { | |
| 276 | + throw new JSONException("Nesting error."); | |
| 277 | + } | |
| 278 | + this.top -= 1; | |
| 279 | + this.mode = this.top == 0 | |
| 280 | + ? 'd' | |
| 281 | + : this.stack[this.top - 1] == null | |
| 282 | + ? 'a' | |
| 283 | + : 'k'; | |
| 284 | + } | |
| 285 | + | |
| 286 | + /** | |
| 287 | + * Push an array or object scope. | |
| 288 | + * @param jo The scope to open. | |
| 289 | + * @throws JSONException If nesting is too deep. | |
| 290 | + */ | |
| 291 | + private void push(JSONObject jo) throws JSONException { | |
| 292 | + if (this.top >= maxdepth) { | |
| 293 | + throw new JSONException("Nesting too deep."); | |
| 294 | + } | |
| 295 | + this.stack[this.top] = jo; | |
| 296 | + this.mode = jo == null ? 'a' : 'k'; | |
| 297 | + this.top += 1; | |
| 298 | + } | |
| 299 | + | |
| 300 | + /** | |
| 301 | + * Make a JSON text of an Object value. If the object has an | |
| 302 | + * value.toJSONString() method, then that method will be used to produce the | |
| 303 | + * JSON text. The method is required to produce a strictly conforming text. | |
| 304 | + * If the object does not contain a toJSONString method (which is the most | |
| 305 | + * common case), then a text will be produced by other means. If the value | |
| 306 | + * is an array or Collection, then a JSONArray will be made from it and its | |
| 307 | + * toJSONString method will be called. If the value is a MAP, then a | |
| 308 | + * JSONObject will be made from it and its toJSONString method will be | |
| 309 | + * called. Otherwise, the value's toString method will be called, and the | |
| 310 | + * result will be quoted. | |
| 311 | + * | |
| 312 | + * <p> | |
| 313 | + * Warning: This method assumes that the data structure is acyclical. | |
| 314 | + * | |
| 315 | + * @param value | |
| 316 | + * The value to be serialized. | |
| 317 | + * @return a printable, displayable, transmittable representation of the | |
| 318 | + * object, beginning with <code>{</code> <small>(left | |
| 319 | + * brace)</small> and ending with <code>}</code> <small>(right | |
| 320 | + * brace)</small>. | |
| 321 | + * @throws JSONException | |
| 322 | + * If the value is or contains an invalid number. | |
| 323 | + */ | |
| 324 | + public static String valueToString(Object value) throws JSONException { | |
| 325 | + if (value == null || value.equals(null)) { | |
| 326 | + return "null"; | |
| 327 | + } | |
| 328 | + if (value instanceof JSONString) { | |
| 329 | + Object object; | |
| 330 | + try { | |
| 331 | + object = ((JSONString) value).toJSONString(); | |
| 332 | + } catch (Exception e) { | |
| 333 | + throw new JSONException(e); | |
| 334 | + } | |
| 335 | + if (object instanceof String) { | |
| 336 | + return (String) object; | |
| 337 | + } | |
| 338 | + throw new JSONException("Bad value from toJSONString: " + object); | |
| 339 | + } | |
| 340 | + if (value instanceof Number) { | |
| 341 | + // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex | |
| 342 | + final String numberAsString = JSONObject.numberToString((Number) value); | |
| 343 | + try { | |
| 344 | + // Use the BigDecimal constructor for it's parser to validate the format. | |
| 345 | + @SuppressWarnings("unused") | |
| 346 | + BigDecimal unused = new BigDecimal(numberAsString); | |
| 347 | + // Close enough to a JSON number that we will return it unquoted | |
| 348 | + return numberAsString; | |
| 349 | + } catch (NumberFormatException ex){ | |
| 350 | + // The Number value is not a valid JSON number. | |
| 351 | + // Instead we will quote it as a string | |
| 352 | + return JSONObject.quote(numberAsString); | |
| 353 | + } | |
| 354 | + } | |
| 355 | + if (value instanceof Boolean || value instanceof JSONObject | |
| 356 | + || value instanceof JSONArray) { | |
| 357 | + return value.toString(); | |
| 358 | + } | |
| 359 | + if (value instanceof Map) { | |
| 360 | + Map<?, ?> map = (Map<?, ?>) value; | |
| 361 | + return new JSONObject(map).toString(); | |
| 362 | + } | |
| 363 | + if (value instanceof Collection) { | |
| 364 | + Collection<?> coll = (Collection<?>) value; | |
| 365 | + return new JSONArray(coll).toString(); | |
| 366 | + } | |
| 367 | + if (value.getClass().isArray()) { | |
| 368 | + return new JSONArray(value).toString(); | |
| 369 | + } | |
| 370 | + if(value instanceof Enum<?>){ | |
| 371 | + return JSONObject.quote(((Enum<?>)value).name()); | |
| 372 | + } | |
| 373 | + return JSONObject.quote(value.toString()); | |
| 374 | + } | |
| 375 | + | |
| 376 | + /** | |
| 377 | + * Append either the value <code>true</code> or the value | |
| 378 | + * <code>false</code>. | |
| 379 | + * @param b A boolean. | |
| 380 | + * @return this | |
| 381 | + * @throws JSONException | |
| 382 | + */ | |
| 383 | + public JSONWriter value(boolean b) throws JSONException { | |
| 384 | + return this.append(b ? "true" : "false"); | |
| 385 | + } | |
| 386 | + | |
| 387 | + /** | |
| 388 | + * Append a double value. | |
| 389 | + * @param d A double. | |
| 390 | + * @return this | |
| 391 | + * @throws JSONException If the number is not finite. | |
| 392 | + */ | |
| 393 | + public JSONWriter value(double d) throws JSONException { | |
| 394 | + return this.value(new Double(d)); | |
| 395 | + } | |
| 396 | + | |
| 397 | + /** | |
| 398 | + * Append a long value. | |
| 399 | + * @param l A long. | |
| 400 | + * @return this | |
| 401 | + * @throws JSONException | |
| 402 | + */ | |
| 403 | + public JSONWriter value(long l) throws JSONException { | |
| 404 | + return this.append(Long.toString(l)); | |
| 405 | + } | |
| 406 | + | |
| 407 | + | |
| 408 | + /** | |
| 409 | + * Append an object value. | |
| 410 | + * @param object The object to append. It can be null, or a Boolean, Number, | |
| 411 | + * String, JSONObject, or JSONArray, or an object that implements JSONString. | |
| 412 | + * @return this | |
| 413 | + * @throws JSONException If the value is out of sequence. | |
| 414 | + */ | |
| 415 | + public JSONWriter value(Object object) throws JSONException { | |
| 416 | + return this.append(valueToString(object)); | |
| 417 | + } | |
| 418 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/LICENSE
0 → 100644
| 1 | +============================================================================ | |
| 2 | + | |
| 3 | +Copyright (c) 2002 JSON.org | |
| 4 | + | |
| 5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | +of this software and associated documentation files (the "Software"), to deal | |
| 7 | +in the Software without restriction, including without limitation the rights | |
| 8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | +copies of the Software, and to permit persons to whom the Software is | |
| 10 | +furnished to do so, subject to the following conditions: | |
| 11 | + | |
| 12 | +The above copyright notice and this permission notice shall be included in all | |
| 13 | +copies or substantial portions of the Software. | |
| 14 | + | |
| 15 | +The Software shall be used for Good, not Evil. | |
| 16 | + | |
| 17 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 18 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 19 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 20 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 21 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 22 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 23 | +SOFTWARE. | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/Property.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +import java.util.Enumeration; | |
| 28 | +import java.util.Properties; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Converts a Property file data into JSONObject and back. | |
| 32 | + * @author JSON.org | |
| 33 | + * @version 2015-05-05 | |
| 34 | + */ | |
| 35 | +public class Property { | |
| 36 | + /** | |
| 37 | + * Converts a property file object into a JSONObject. The property file object is a table of name value pairs. | |
| 38 | + * @param properties java.util.Properties | |
| 39 | + * @return JSONObject | |
| 40 | + * @throws JSONException | |
| 41 | + */ | |
| 42 | + public static JSONObject toJSONObject(Properties properties) throws JSONException { | |
| 43 | + // can't use the new constructor for Android support | |
| 44 | + // JSONObject jo = new JSONObject(properties == null ? 0 : properties.size()); | |
| 45 | + JSONObject jo = new JSONObject(); | |
| 46 | + if (properties != null && !properties.isEmpty()) { | |
| 47 | + Enumeration<?> enumProperties = properties.propertyNames(); | |
| 48 | + while(enumProperties.hasMoreElements()) { | |
| 49 | + String name = (String)enumProperties.nextElement(); | |
| 50 | + jo.put(name, properties.getProperty(name)); | |
| 51 | + } | |
| 52 | + } | |
| 53 | + return jo; | |
| 54 | + } | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * Converts the JSONObject into a property file object. | |
| 58 | + * @param jo JSONObject | |
| 59 | + * @return java.util.Properties | |
| 60 | + * @throws JSONException | |
| 61 | + */ | |
| 62 | + public static Properties toProperties(JSONObject jo) throws JSONException { | |
| 63 | + Properties properties = new Properties(); | |
| 64 | + if (jo != null) { | |
| 65 | + // Don't use the new entrySet API to maintain Android support | |
| 66 | + for (final String key : jo.keySet()) { | |
| 67 | + Object value = jo.opt(key); | |
| 68 | + if (!JSONObject.NULL.equals(value)) { | |
| 69 | + properties.put(key, value.toString()); | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | + return properties; | |
| 74 | + } | |
| 75 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/README.md
0 → 100644
| 1 | +JSON in Java [package org.json] | |
| 2 | +=============================== | |
| 3 | + | |
| 4 | +[](https://mvnrepository.com/artifact/org.json/json) | |
| 5 | + | |
| 6 | +JSON is a light-weight, language independent, data interchange format. | |
| 7 | +See http://www.JSON.org/ | |
| 8 | + | |
| 9 | +The files in this package implement JSON encoders/decoders in Java. | |
| 10 | +It also includes the capability to convert between JSON and XML, HTTP | |
| 11 | +headers, Cookies, and CDL. | |
| 12 | + | |
| 13 | +This is a reference implementation. There is a large number of JSON packages | |
| 14 | +in Java. Perhaps someday the Java community will standardize on one. Until | |
| 15 | +then, choose carefully. | |
| 16 | + | |
| 17 | +The license includes this restriction: "The software shall be used for good, | |
| 18 | +not evil." If your conscience cannot live with that, then choose a different | |
| 19 | +package. | |
| 20 | + | |
| 21 | +The package compiles on Java 1.6-1.8. | |
| 22 | + | |
| 23 | + | |
| 24 | +**JSONObject.java**: The `JSONObject` can parse text from a `String` or a `JSONTokener` | |
| 25 | +to produce a map-like object. The object provides methods for manipulating its | |
| 26 | +contents, and for producing a JSON compliant object serialization. | |
| 27 | + | |
| 28 | +**JSONArray.java**: The `JSONArray` can parse text from a String or a `JSONTokener` | |
| 29 | +to produce a vector-like object. The object provides methods for manipulating | |
| 30 | +its contents, and for producing a JSON compliant array serialization. | |
| 31 | + | |
| 32 | +**JSONTokener.java**: The `JSONTokener` breaks a text into a sequence of individual | |
| 33 | +tokens. It can be constructed from a `String`, `Reader`, or `InputStream`. | |
| 34 | + | |
| 35 | +**JSONException.java**: The `JSONException` is the standard exception type thrown | |
| 36 | +by this package. | |
| 37 | + | |
| 38 | +**JSONPointer.java**: Implementation of | |
| 39 | +[JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901). Supports | |
| 40 | +JSON Pointers both in the form of string representation and URI fragment | |
| 41 | +representation. | |
| 42 | + | |
| 43 | +**JSONString.java**: The `JSONString` interface requires a `toJSONString` method, | |
| 44 | +allowing an object to provide its own serialization. | |
| 45 | + | |
| 46 | +**JSONStringer.java**: The `JSONStringer` provides a convenient facility for | |
| 47 | +building JSON strings. | |
| 48 | + | |
| 49 | +**JSONWriter.java**: The `JSONWriter` provides a convenient facility for building | |
| 50 | +JSON text through a writer. | |
| 51 | + | |
| 52 | + | |
| 53 | +**CDL.java**: `CDL` provides support for converting between JSON and comma | |
| 54 | +delimited lists. | |
| 55 | + | |
| 56 | +**Cookie.java**: `Cookie` provides support for converting between JSON and cookies. | |
| 57 | + | |
| 58 | +**CookieList.java**: `CookieList` provides support for converting between JSON and | |
| 59 | +cookie lists. | |
| 60 | + | |
| 61 | +**HTTP.java**: `HTTP` provides support for converting between JSON and HTTP headers. | |
| 62 | + | |
| 63 | +**HTTPTokener.java**: `HTTPTokener` extends `JSONTokener` for parsing HTTP headers. | |
| 64 | + | |
| 65 | +**XML.java**: `XML` provides support for converting between JSON and XML. | |
| 66 | + | |
| 67 | +**JSONML.java**: `JSONML` provides support for converting between JSONML and XML. | |
| 68 | + | |
| 69 | +**XMLTokener.java**: `XMLTokener` extends `JSONTokener` for parsing XML text. | |
| 70 | + | |
| 71 | +Unit tests are maintained in a separate project. Contributing developers can test | |
| 72 | +JSON-java pull requests with the code in this project: | |
| 73 | +https://github.com/stleary/JSON-Java-unit-test | |
| 74 | + | |
| 75 | +Numeric types in this package comply with | |
| 76 | +[ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) and | |
| 77 | +[RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159#section-6). | |
| 78 | +This package fully supports `Integer`, `Long`, and `Double` Java types. Partial support | |
| 79 | +for `BigInteger` and `BigDecimal` values in `JSONObject` and `JSONArray` objects is provided | |
| 80 | +in the form of `get()`, `opt()`, and `put()` API methods. | |
| 81 | + | |
| 82 | +Although 1.6 compatibility is currently supported, it is not a project goal and may be | |
| 83 | +removed in some future release. | |
| 84 | + | |
| 85 | +In compliance with RFC7159 page 10 section 9, the parser is more lax with what is valid | |
| 86 | +JSON than the Generator. For Example, the tab character (U+0009) is allowed when reading | |
| 87 | +JSON Text strings, but when output by the Generator, tab is properly converted to \t in | |
| 88 | +the string. Other instances may occur where reading invalid JSON text does not cause an | |
| 89 | +error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or | |
| 90 | +invalid number formats (1.2e6.3) will cause errors as such documents can not be read | |
| 91 | + reliably. | |
| 92 | + | |
| 93 | +Release history: | |
| 94 | + | |
| 95 | +~~~ | |
| 96 | +20180130 Recent commits | |
| 97 | + | |
| 98 | +20171018 Checkpoint for recent commits. | |
| 99 | + | |
| 100 | +20170516 Roll up recent commits. | |
| 101 | + | |
| 102 | +20160810 Revert code that was breaking opt*() methods. | |
| 103 | + | |
| 104 | +20160807 This release contains a bug in the JSONObject.opt*() and JSONArray.opt*() methods, | |
| 105 | +it is not recommended for use. | |
| 106 | +Java 1.6 compatability fixed, JSONArray.toList() and JSONObject.toMap(), | |
| 107 | +RFC4180 compatibility, JSONPointer, some exception fixes, optional XML type conversion. | |
| 108 | +Contains the latest code as of 7 Aug, 2016 | |
| 109 | + | |
| 110 | +20160212 Java 1.6 compatibility, OSGi bundle. Contains the latest code as of 12 Feb, 2016. | |
| 111 | + | |
| 112 | +20151123 JSONObject and JSONArray initialization with generics. Contains the | |
| 113 | +latest code as of 23 Nov, 2015. | |
| 114 | + | |
| 115 | +20150729 Checkpoint for Maven central repository release. Contains the latest code | |
| 116 | +as of 29 July, 2015. | |
| 117 | +~~~ | |
| 118 | + | |
| 119 | + | |
| 120 | +JSON-java releases can be found by searching the Maven repository for groupId "org.json" | |
| 121 | +and artifactId "json". For example: | |
| 122 | +https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.json%22%20AND%20a%3A%22json%22 | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/XML.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2015 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +import java.util.Iterator; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * This provides static methods to convert an XML text into a JSONObject, and to | |
| 31 | + * covert a JSONObject into an XML text. | |
| 32 | + * | |
| 33 | + * @author JSON.org | |
| 34 | + * @version 2016-08-10 | |
| 35 | + */ | |
| 36 | +@SuppressWarnings("boxing") | |
| 37 | +public class XML { | |
| 38 | + /** The Character '&'. */ | |
| 39 | + public static final Character AMP = '&'; | |
| 40 | + | |
| 41 | + /** The Character '''. */ | |
| 42 | + public static final Character APOS = '\''; | |
| 43 | + | |
| 44 | + /** The Character '!'. */ | |
| 45 | + public static final Character BANG = '!'; | |
| 46 | + | |
| 47 | + /** The Character '='. */ | |
| 48 | + public static final Character EQ = '='; | |
| 49 | + | |
| 50 | + /** The Character '>'. */ | |
| 51 | + public static final Character GT = '>'; | |
| 52 | + | |
| 53 | + /** The Character '<'. */ | |
| 54 | + public static final Character LT = '<'; | |
| 55 | + | |
| 56 | + /** The Character '?'. */ | |
| 57 | + public static final Character QUEST = '?'; | |
| 58 | + | |
| 59 | + /** The Character '"'. */ | |
| 60 | + public static final Character QUOT = '"'; | |
| 61 | + | |
| 62 | + /** The Character '/'. */ | |
| 63 | + public static final Character SLASH = '/'; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Creates an iterator for navigating Code Points in a string instead of | |
| 67 | + * characters. Once Java7 support is dropped, this can be replaced with | |
| 68 | + * <code> | |
| 69 | + * string.codePoints() | |
| 70 | + * </code> | |
| 71 | + * which is available in Java8 and above. | |
| 72 | + * | |
| 73 | + * @see <a href= | |
| 74 | + * "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a> | |
| 75 | + */ | |
| 76 | + private static Iterable<Integer> codePointIterator(final String string) { | |
| 77 | + return new Iterable<Integer>() { | |
| 78 | + @Override | |
| 79 | + public Iterator<Integer> iterator() { | |
| 80 | + return new Iterator<Integer>() { | |
| 81 | + private int nextIndex = 0; | |
| 82 | + private int length = string.length(); | |
| 83 | + | |
| 84 | + @Override | |
| 85 | + public boolean hasNext() { | |
| 86 | + return this.nextIndex < this.length; | |
| 87 | + } | |
| 88 | + | |
| 89 | + @Override | |
| 90 | + public Integer next() { | |
| 91 | + int result = string.codePointAt(this.nextIndex); | |
| 92 | + this.nextIndex += Character.charCount(result); | |
| 93 | + return result; | |
| 94 | + } | |
| 95 | + | |
| 96 | + @Override | |
| 97 | + public void remove() { | |
| 98 | + throw new UnsupportedOperationException(); | |
| 99 | + } | |
| 100 | + }; | |
| 101 | + } | |
| 102 | + }; | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Replace special characters with XML escapes: | |
| 107 | + * | |
| 108 | + * <pre> | |
| 109 | + * & <small>(ampersand)</small> is replaced by &amp; | |
| 110 | + * < <small>(less than)</small> is replaced by &lt; | |
| 111 | + * > <small>(greater than)</small> is replaced by &gt; | |
| 112 | + * " <small>(double quote)</small> is replaced by &quot; | |
| 113 | + * ' <small>(single quote / apostrophe)</small> is replaced by &apos; | |
| 114 | + * </pre> | |
| 115 | + * | |
| 116 | + * @param string | |
| 117 | + * The string to be escaped. | |
| 118 | + * @return The escaped string. | |
| 119 | + */ | |
| 120 | + public static String escape(String string) { | |
| 121 | + StringBuilder sb = new StringBuilder(string.length()); | |
| 122 | + for (final int cp : codePointIterator(string)) { | |
| 123 | + switch (cp) { | |
| 124 | + case '&': | |
| 125 | + sb.append("&"); | |
| 126 | + break; | |
| 127 | + case '<': | |
| 128 | + sb.append("<"); | |
| 129 | + break; | |
| 130 | + case '>': | |
| 131 | + sb.append(">"); | |
| 132 | + break; | |
| 133 | + case '"': | |
| 134 | + sb.append("""); | |
| 135 | + break; | |
| 136 | + case '\'': | |
| 137 | + sb.append("'"); | |
| 138 | + break; | |
| 139 | + default: | |
| 140 | + if (mustEscape(cp)) { | |
| 141 | + sb.append("&#x"); | |
| 142 | + sb.append(Integer.toHexString(cp)); | |
| 143 | + sb.append(';'); | |
| 144 | + } else { | |
| 145 | + sb.appendCodePoint(cp); | |
| 146 | + } | |
| 147 | + } | |
| 148 | + } | |
| 149 | + return sb.toString(); | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * @param cp code point to test | |
| 154 | + * @return true if the code point is not valid for an XML | |
| 155 | + */ | |
| 156 | + private static boolean mustEscape(int cp) { | |
| 157 | + /* Valid range from https://www.w3.org/TR/REC-xml/#charsets | |
| 158 | + * | |
| 159 | + * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] | |
| 160 | + * | |
| 161 | + * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. | |
| 162 | + */ | |
| 163 | + // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) | |
| 164 | + // all ISO control characters are out of range except tabs and new lines | |
| 165 | + return (Character.isISOControl(cp) | |
| 166 | + && cp != 0x9 | |
| 167 | + && cp != 0xA | |
| 168 | + && cp != 0xD | |
| 169 | + ) || !( | |
| 170 | + // valid the range of acceptable characters that aren't control | |
| 171 | + (cp >= 0x20 && cp <= 0xD7FF) | |
| 172 | + || (cp >= 0xE000 && cp <= 0xFFFD) | |
| 173 | + || (cp >= 0x10000 && cp <= 0x10FFFF) | |
| 174 | + ) | |
| 175 | + ; | |
| 176 | + } | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * Removes XML escapes from the string. | |
| 180 | + * | |
| 181 | + * @param string | |
| 182 | + * string to remove escapes from | |
| 183 | + * @return string with converted entities | |
| 184 | + */ | |
| 185 | + public static String unescape(String string) { | |
| 186 | + StringBuilder sb = new StringBuilder(string.length()); | |
| 187 | + for (int i = 0, length = string.length(); i < length; i++) { | |
| 188 | + char c = string.charAt(i); | |
| 189 | + if (c == '&') { | |
| 190 | + final int semic = string.indexOf(';', i); | |
| 191 | + if (semic > i) { | |
| 192 | + final String entity = string.substring(i + 1, semic); | |
| 193 | + sb.append(XMLTokener.unescapeEntity(entity)); | |
| 194 | + // skip past the entity we just parsed. | |
| 195 | + i += entity.length() + 1; | |
| 196 | + } else { | |
| 197 | + // this shouldn't happen in most cases since the parser | |
| 198 | + // errors on unclosed entries. | |
| 199 | + sb.append(c); | |
| 200 | + } | |
| 201 | + } else { | |
| 202 | + // not part of an entity | |
| 203 | + sb.append(c); | |
| 204 | + } | |
| 205 | + } | |
| 206 | + return sb.toString(); | |
| 207 | + } | |
| 208 | + | |
| 209 | + /** | |
| 210 | + * Throw an exception if the string contains whitespace. Whitespace is not | |
| 211 | + * allowed in tagNames and attributes. | |
| 212 | + * | |
| 213 | + * @param string | |
| 214 | + * A string. | |
| 215 | + * @throws JSONException Thrown if the string contains whitespace or is empty. | |
| 216 | + */ | |
| 217 | + public static void noSpace(String string) throws JSONException { | |
| 218 | + int i, length = string.length(); | |
| 219 | + if (length == 0) { | |
| 220 | + throw new JSONException("Empty string."); | |
| 221 | + } | |
| 222 | + for (i = 0; i < length; i += 1) { | |
| 223 | + if (Character.isWhitespace(string.charAt(i))) { | |
| 224 | + throw new JSONException("'" + string | |
| 225 | + + "' contains a space character."); | |
| 226 | + } | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + /** | |
| 231 | + * Scan the content following the named tag, attaching it to the context. | |
| 232 | + * | |
| 233 | + * @param x | |
| 234 | + * The XMLTokener containing the source string. | |
| 235 | + * @param context | |
| 236 | + * The JSONObject that will include the new material. | |
| 237 | + * @param name | |
| 238 | + * The tag name. | |
| 239 | + * @return true if the close tag is processed. | |
| 240 | + * @throws JSONException | |
| 241 | + */ | |
| 242 | + private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) | |
| 243 | + throws JSONException { | |
| 244 | + char c; | |
| 245 | + int i; | |
| 246 | + JSONObject jsonobject = null; | |
| 247 | + String string; | |
| 248 | + String tagName; | |
| 249 | + Object token; | |
| 250 | + | |
| 251 | + // Test for and skip past these forms: | |
| 252 | + // <!-- ... --> | |
| 253 | + // <! ... > | |
| 254 | + // <![ ... ]]> | |
| 255 | + // <? ... ?> | |
| 256 | + // Report errors for these forms: | |
| 257 | + // <> | |
| 258 | + // <= | |
| 259 | + // << | |
| 260 | + | |
| 261 | + token = x.nextToken(); | |
| 262 | + | |
| 263 | + // <! | |
| 264 | + | |
| 265 | + if (token == BANG) { | |
| 266 | + c = x.next(); | |
| 267 | + if (c == '-') { | |
| 268 | + if (x.next() == '-') { | |
| 269 | + x.skipPast("-->"); | |
| 270 | + return false; | |
| 271 | + } | |
| 272 | + x.back(); | |
| 273 | + } else if (c == '[') { | |
| 274 | + token = x.nextToken(); | |
| 275 | + if ("CDATA".equals(token)) { | |
| 276 | + if (x.next() == '[') { | |
| 277 | + string = x.nextCDATA(); | |
| 278 | + if (string.length() > 0) { | |
| 279 | + context.accumulate("content", string); | |
| 280 | + } | |
| 281 | + return false; | |
| 282 | + } | |
| 283 | + } | |
| 284 | + throw x.syntaxError("Expected 'CDATA['"); | |
| 285 | + } | |
| 286 | + i = 1; | |
| 287 | + do { | |
| 288 | + token = x.nextMeta(); | |
| 289 | + if (token == null) { | |
| 290 | + throw x.syntaxError("Missing '>' after '<!'."); | |
| 291 | + } else if (token == LT) { | |
| 292 | + i += 1; | |
| 293 | + } else if (token == GT) { | |
| 294 | + i -= 1; | |
| 295 | + } | |
| 296 | + } while (i > 0); | |
| 297 | + return false; | |
| 298 | + } else if (token == QUEST) { | |
| 299 | + | |
| 300 | + // <? | |
| 301 | + x.skipPast("?>"); | |
| 302 | + return false; | |
| 303 | + } else if (token == SLASH) { | |
| 304 | + | |
| 305 | + // Close tag </ | |
| 306 | + | |
| 307 | + token = x.nextToken(); | |
| 308 | + if (name == null) { | |
| 309 | + throw x.syntaxError("Mismatched close tag " + token); | |
| 310 | + } | |
| 311 | + if (!token.equals(name)) { | |
| 312 | + throw x.syntaxError("Mismatched " + name + " and " + token); | |
| 313 | + } | |
| 314 | + if (x.nextToken() != GT) { | |
| 315 | + throw x.syntaxError("Misshaped close tag"); | |
| 316 | + } | |
| 317 | + return true; | |
| 318 | + | |
| 319 | + } else if (token instanceof Character) { | |
| 320 | + throw x.syntaxError("Misshaped tag"); | |
| 321 | + | |
| 322 | + // Open tag < | |
| 323 | + | |
| 324 | + } else { | |
| 325 | + tagName = (String) token; | |
| 326 | + token = null; | |
| 327 | + jsonobject = new JSONObject(); | |
| 328 | + for (;;) { | |
| 329 | + if (token == null) { | |
| 330 | + token = x.nextToken(); | |
| 331 | + } | |
| 332 | + // attribute = value | |
| 333 | + if (token instanceof String) { | |
| 334 | + string = (String) token; | |
| 335 | + token = x.nextToken(); | |
| 336 | + if (token == EQ) { | |
| 337 | + token = x.nextToken(); | |
| 338 | + if (!(token instanceof String)) { | |
| 339 | + throw x.syntaxError("Missing value"); | |
| 340 | + } | |
| 341 | + jsonobject.accumulate(string, | |
| 342 | + keepStrings ? ((String)token) : stringToValue((String) token)); | |
| 343 | + token = null; | |
| 344 | + } else { | |
| 345 | + jsonobject.accumulate(string, ""); | |
| 346 | + } | |
| 347 | + | |
| 348 | + | |
| 349 | + } else if (token == SLASH) { | |
| 350 | + // Empty tag <.../> | |
| 351 | + if (x.nextToken() != GT) { | |
| 352 | + throw x.syntaxError("Misshaped tag"); | |
| 353 | + } | |
| 354 | + if (jsonobject.length() > 0) { | |
| 355 | + context.accumulate(tagName, jsonobject); | |
| 356 | + } else { | |
| 357 | + context.accumulate(tagName, ""); | |
| 358 | + } | |
| 359 | + return false; | |
| 360 | + | |
| 361 | + } else if (token == GT) { | |
| 362 | + // Content, between <...> and </...> | |
| 363 | + for (;;) { | |
| 364 | + token = x.nextContent(); | |
| 365 | + if (token == null) { | |
| 366 | + if (tagName != null) { | |
| 367 | + throw x.syntaxError("Unclosed tag " + tagName); | |
| 368 | + } | |
| 369 | + return false; | |
| 370 | + } else if (token instanceof String) { | |
| 371 | + string = (String) token; | |
| 372 | + if (string.length() > 0) { | |
| 373 | + jsonobject.accumulate("content", | |
| 374 | + keepStrings ? string : stringToValue(string)); | |
| 375 | + } | |
| 376 | + | |
| 377 | + } else if (token == LT) { | |
| 378 | + // Nested element | |
| 379 | + if (parse(x, jsonobject, tagName,keepStrings)) { | |
| 380 | + if (jsonobject.length() == 0) { | |
| 381 | + context.accumulate(tagName, ""); | |
| 382 | + } else if (jsonobject.length() == 1 | |
| 383 | + && jsonobject.opt("content") != null) { | |
| 384 | + context.accumulate(tagName, | |
| 385 | + jsonobject.opt("content")); | |
| 386 | + } else { | |
| 387 | + context.accumulate(tagName, jsonobject); | |
| 388 | + } | |
| 389 | + return false; | |
| 390 | + } | |
| 391 | + } | |
| 392 | + } | |
| 393 | + } else { | |
| 394 | + throw x.syntaxError("Misshaped tag"); | |
| 395 | + } | |
| 396 | + } | |
| 397 | + } | |
| 398 | + } | |
| 399 | + | |
| 400 | + /** | |
| 401 | + * This method is the same as {@link JSONObject#stringToValue(String)}. | |
| 402 | + * | |
| 403 | + * @param string String to convert | |
| 404 | + * @return JSON value of this string or the string | |
| 405 | + */ | |
| 406 | + // To maintain compatibility with the Android API, this method is a direct copy of | |
| 407 | + // the one in JSONObject. Changes made here should be reflected there. | |
| 408 | + public static Object stringToValue(String string) { | |
| 409 | + if (string.equals("")) { | |
| 410 | + return string; | |
| 411 | + } | |
| 412 | + if (string.equalsIgnoreCase("true")) { | |
| 413 | + return Boolean.TRUE; | |
| 414 | + } | |
| 415 | + if (string.equalsIgnoreCase("false")) { | |
| 416 | + return Boolean.FALSE; | |
| 417 | + } | |
| 418 | + if (string.equalsIgnoreCase("null")) { | |
| 419 | + return JSONObject.NULL; | |
| 420 | + } | |
| 421 | + | |
| 422 | + /* | |
| 423 | + * If it might be a number, try converting it. If a number cannot be | |
| 424 | + * produced, then the value will just be a string. | |
| 425 | + */ | |
| 426 | + | |
| 427 | + char initial = string.charAt(0); | |
| 428 | + if ((initial >= '0' && initial <= '9') || initial == '-') { | |
| 429 | + try { | |
| 430 | + // if we want full Big Number support this block can be replaced with: | |
| 431 | + // return stringToNumber(string); | |
| 432 | + if (string.indexOf('.') > -1 || string.indexOf('e') > -1 | |
| 433 | + || string.indexOf('E') > -1 || "-0".equals(string)) { | |
| 434 | + Double d = Double.valueOf(string); | |
| 435 | + if (!d.isInfinite() && !d.isNaN()) { | |
| 436 | + return d; | |
| 437 | + } | |
| 438 | + } else { | |
| 439 | + Long myLong = Long.valueOf(string); | |
| 440 | + if (string.equals(myLong.toString())) { | |
| 441 | + if (myLong.longValue() == myLong.intValue()) { | |
| 442 | + return Integer.valueOf(myLong.intValue()); | |
| 443 | + } | |
| 444 | + return myLong; | |
| 445 | + } | |
| 446 | + } | |
| 447 | + } catch (Exception ignore) { | |
| 448 | + } | |
| 449 | + } | |
| 450 | + return string; | |
| 451 | + } | |
| 452 | + | |
| 453 | + /** | |
| 454 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 455 | + * JSONObject. Some information may be lost in this transformation because | |
| 456 | + * JSON is a data format and XML is a document format. XML uses elements, | |
| 457 | + * attributes, and content text, while JSON uses unordered collections of | |
| 458 | + * name/value pairs and arrays of values. JSON does not does not like to | |
| 459 | + * distinguish between elements and attributes. Sequences of similar | |
| 460 | + * elements are represented as JSONArrays. Content text may be placed in a | |
| 461 | + * "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code> | |
| 462 | + * are ignored. | |
| 463 | + * | |
| 464 | + * @param string | |
| 465 | + * The source string. | |
| 466 | + * @return A JSONObject containing the structured data from the XML string. | |
| 467 | + * @throws JSONException Thrown if there is an errors while parsing the string | |
| 468 | + */ | |
| 469 | + public static JSONObject toJSONObject(String string) throws JSONException { | |
| 470 | + return toJSONObject(string, false); | |
| 471 | + } | |
| 472 | + | |
| 473 | + | |
| 474 | + /** | |
| 475 | + * Convert a well-formed (but not necessarily valid) XML string into a | |
| 476 | + * JSONObject. Some information may be lost in this transformation because | |
| 477 | + * JSON is a data format and XML is a document format. XML uses elements, | |
| 478 | + * attributes, and content text, while JSON uses unordered collections of | |
| 479 | + * name/value pairs and arrays of values. JSON does not does not like to | |
| 480 | + * distinguish between elements and attributes. Sequences of similar | |
| 481 | + * elements are represented as JSONArrays. Content text may be placed in a | |
| 482 | + * "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code> | |
| 483 | + * are ignored. | |
| 484 | + * | |
| 485 | + * All values are converted as strings, for 1, 01, 29.0 will not be coerced to | |
| 486 | + * numbers but will instead be the exact value as seen in the XML document. | |
| 487 | + * | |
| 488 | + * @param string | |
| 489 | + * The source string. | |
| 490 | + * @param keepStrings If true, then values will not be coerced into boolean | |
| 491 | + * or numeric values and will instead be left as strings | |
| 492 | + * @return A JSONObject containing the structured data from the XML string. | |
| 493 | + * @throws JSONException Thrown if there is an errors while parsing the string | |
| 494 | + */ | |
| 495 | + public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { | |
| 496 | + JSONObject jo = new JSONObject(); | |
| 497 | + XMLTokener x = new XMLTokener(string); | |
| 498 | + while (x.more()) { | |
| 499 | + x.skipPast("<"); | |
| 500 | + if(x.more()) { | |
| 501 | + parse(x, jo, null, keepStrings); | |
| 502 | + } | |
| 503 | + } | |
| 504 | + return jo; | |
| 505 | + } | |
| 506 | + /** | |
| 507 | + * Convert a JSONObject into a well-formed, element-normal XML string. | |
| 508 | + * | |
| 509 | + * @param object | |
| 510 | + * A JSONObject. | |
| 511 | + * @return A string. | |
| 512 | + * @throws JSONException Thrown if there is an error parsing the string | |
| 513 | + */ | |
| 514 | + public static String toString(Object object) throws JSONException { | |
| 515 | + return toString(object, null); | |
| 516 | + } | |
| 517 | + | |
| 518 | + /** | |
| 519 | + * Convert a JSONObject into a well-formed, element-normal XML string. | |
| 520 | + * | |
| 521 | + * @param object | |
| 522 | + * A JSONObject. | |
| 523 | + * @param tagName | |
| 524 | + * The optional name of the enclosing tag. | |
| 525 | + * @return A string. | |
| 526 | + * @throws JSONException Thrown if there is an error parsing the string | |
| 527 | + */ | |
| 528 | + public static String toString(final Object object, final String tagName) | |
| 529 | + throws JSONException { | |
| 530 | + StringBuilder sb = new StringBuilder(); | |
| 531 | + JSONArray ja; | |
| 532 | + JSONObject jo; | |
| 533 | + String string; | |
| 534 | + | |
| 535 | + if (object instanceof JSONObject) { | |
| 536 | + | |
| 537 | + // Emit <tagName> | |
| 538 | + if (tagName != null) { | |
| 539 | + sb.append('<'); | |
| 540 | + sb.append(tagName); | |
| 541 | + sb.append('>'); | |
| 542 | + } | |
| 543 | + | |
| 544 | + // Loop thru the keys. | |
| 545 | + // don't use the new entrySet accessor to maintain Android Support | |
| 546 | + jo = (JSONObject) object; | |
| 547 | + for (final String key : jo.keySet()) { | |
| 548 | + Object value = jo.opt(key); | |
| 549 | + if (value == null) { | |
| 550 | + value = ""; | |
| 551 | + } else if (value.getClass().isArray()) { | |
| 552 | + value = new JSONArray(value); | |
| 553 | + } | |
| 554 | + | |
| 555 | + // Emit content in body | |
| 556 | + if ("content".equals(key)) { | |
| 557 | + if (value instanceof JSONArray) { | |
| 558 | + ja = (JSONArray) value; | |
| 559 | + int jaLength = ja.length(); | |
| 560 | + // don't use the new iterator API to maintain support for Android | |
| 561 | + for (int i = 0; i < jaLength; i++) { | |
| 562 | + if (i > 0) { | |
| 563 | + sb.append('\n'); | |
| 564 | + } | |
| 565 | + Object val = ja.opt(i); | |
| 566 | + sb.append(escape(val.toString())); | |
| 567 | + } | |
| 568 | + } else { | |
| 569 | + sb.append(escape(value.toString())); | |
| 570 | + } | |
| 571 | + | |
| 572 | + // Emit an array of similar keys | |
| 573 | + | |
| 574 | + } else if (value instanceof JSONArray) { | |
| 575 | + ja = (JSONArray) value; | |
| 576 | + int jaLength = ja.length(); | |
| 577 | + // don't use the new iterator API to maintain support for Android | |
| 578 | + for (int i = 0; i < jaLength; i++) { | |
| 579 | + Object val = ja.opt(i); | |
| 580 | + if (val instanceof JSONArray) { | |
| 581 | + sb.append('<'); | |
| 582 | + sb.append(key); | |
| 583 | + sb.append('>'); | |
| 584 | + sb.append(toString(val)); | |
| 585 | + sb.append("</"); | |
| 586 | + sb.append(key); | |
| 587 | + sb.append('>'); | |
| 588 | + } else { | |
| 589 | + sb.append(toString(val, key)); | |
| 590 | + } | |
| 591 | + } | |
| 592 | + } else if ("".equals(value)) { | |
| 593 | + sb.append('<'); | |
| 594 | + sb.append(key); | |
| 595 | + sb.append("/>"); | |
| 596 | + | |
| 597 | + // Emit a new tag <k> | |
| 598 | + | |
| 599 | + } else { | |
| 600 | + sb.append(toString(value, key)); | |
| 601 | + } | |
| 602 | + } | |
| 603 | + if (tagName != null) { | |
| 604 | + | |
| 605 | + // Emit the </tagname> close tag | |
| 606 | + sb.append("</"); | |
| 607 | + sb.append(tagName); | |
| 608 | + sb.append('>'); | |
| 609 | + } | |
| 610 | + return sb.toString(); | |
| 611 | + | |
| 612 | + } | |
| 613 | + | |
| 614 | + if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { | |
| 615 | + if(object.getClass().isArray()) { | |
| 616 | + ja = new JSONArray(object); | |
| 617 | + } else { | |
| 618 | + ja = (JSONArray) object; | |
| 619 | + } | |
| 620 | + int jaLength = ja.length(); | |
| 621 | + // don't use the new iterator API to maintain support for Android | |
| 622 | + for (int i = 0; i < jaLength; i++) { | |
| 623 | + Object val = ja.opt(i); | |
| 624 | + // XML does not have good support for arrays. If an array | |
| 625 | + // appears in a place where XML is lacking, synthesize an | |
| 626 | + // <array> element. | |
| 627 | + sb.append(toString(val, tagName == null ? "array" : tagName)); | |
| 628 | + } | |
| 629 | + return sb.toString(); | |
| 630 | + } | |
| 631 | + | |
| 632 | + string = (object == null) ? "null" : escape(object.toString()); | |
| 633 | + return (tagName == null) ? "\"" + string + "\"" | |
| 634 | + : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName | |
| 635 | + + ">" + string + "</" + tagName + ">"; | |
| 636 | + | |
| 637 | + } | |
| 638 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/org/json/XMLTokener.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.org.json; | |
| 2 | + | |
| 3 | +/* | |
| 4 | +Copyright (c) 2002 JSON.org | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | + | |
| 16 | +The Software shall be used for Good, not Evil. | |
| 17 | + | |
| 18 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 21 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 24 | +SOFTWARE. | |
| 25 | +*/ | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * The XMLTokener extends the JSONTokener to provide additional methods | |
| 29 | + * for the parsing of XML texts. | |
| 30 | + * @author JSON.org | |
| 31 | + * @version 2015-12-09 | |
| 32 | + */ | |
| 33 | +public class XMLTokener extends JSONTokener { | |
| 34 | + | |
| 35 | + | |
| 36 | + /** The table of entity values. It initially contains Character values for | |
| 37 | + * amp, apos, gt, lt, quot. | |
| 38 | + */ | |
| 39 | + public static final java.util.HashMap<String, Character> entity; | |
| 40 | + | |
| 41 | + static { | |
| 42 | + entity = new java.util.HashMap<String, Character>(8); | |
| 43 | + entity.put("amp", XML.AMP); | |
| 44 | + entity.put("apos", XML.APOS); | |
| 45 | + entity.put("gt", XML.GT); | |
| 46 | + entity.put("lt", XML.LT); | |
| 47 | + entity.put("quot", XML.QUOT); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Construct an XMLTokener from a string. | |
| 52 | + * @param s A source string. | |
| 53 | + */ | |
| 54 | + public XMLTokener(String s) { | |
| 55 | + super(s); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * Get the text in the CDATA block. | |
| 60 | + * @return The string up to the <code>]]></code>. | |
| 61 | + * @throws JSONException If the <code>]]></code> is not found. | |
| 62 | + */ | |
| 63 | + public String nextCDATA() throws JSONException { | |
| 64 | + char c; | |
| 65 | + int i; | |
| 66 | + StringBuilder sb = new StringBuilder(); | |
| 67 | + while (more()) { | |
| 68 | + c = next(); | |
| 69 | + sb.append(c); | |
| 70 | + i = sb.length() - 3; | |
| 71 | + if (i >= 0 && sb.charAt(i) == ']' && | |
| 72 | + sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { | |
| 73 | + sb.setLength(i); | |
| 74 | + return sb.toString(); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + throw syntaxError("Unclosed CDATA"); | |
| 78 | + } | |
| 79 | + | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Get the next XML outer token, trimming whitespace. There are two kinds | |
| 83 | + * of tokens: the '<' character which begins a markup tag, and the content | |
| 84 | + * text between markup tags. | |
| 85 | + * | |
| 86 | + * @return A string, or a '<' Character, or null if there is no more | |
| 87 | + * source text. | |
| 88 | + * @throws JSONException | |
| 89 | + */ | |
| 90 | + public Object nextContent() throws JSONException { | |
| 91 | + char c; | |
| 92 | + StringBuilder sb; | |
| 93 | + do { | |
| 94 | + c = next(); | |
| 95 | + } while (Character.isWhitespace(c)); | |
| 96 | + if (c == 0) { | |
| 97 | + return null; | |
| 98 | + } | |
| 99 | + if (c == '<') { | |
| 100 | + return XML.LT; | |
| 101 | + } | |
| 102 | + sb = new StringBuilder(); | |
| 103 | + for (;;) { | |
| 104 | + if (c == 0) { | |
| 105 | + return sb.toString().trim(); | |
| 106 | + } | |
| 107 | + if (c == '<') { | |
| 108 | + back(); | |
| 109 | + return sb.toString().trim(); | |
| 110 | + } | |
| 111 | + if (c == '&') { | |
| 112 | + sb.append(nextEntity(c)); | |
| 113 | + } else { | |
| 114 | + sb.append(c); | |
| 115 | + } | |
| 116 | + c = next(); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * Return the next entity. These entities are translated to Characters: | |
| 123 | + * <code>& ' > < "</code>. | |
| 124 | + * @param ampersand An ampersand character. | |
| 125 | + * @return A Character or an entity String if the entity is not recognized. | |
| 126 | + * @throws JSONException If missing ';' in XML entity. | |
| 127 | + */ | |
| 128 | + public Object nextEntity(char ampersand) throws JSONException { | |
| 129 | + StringBuilder sb = new StringBuilder(); | |
| 130 | + for (;;) { | |
| 131 | + char c = next(); | |
| 132 | + if (Character.isLetterOrDigit(c) || c == '#') { | |
| 133 | + sb.append(Character.toLowerCase(c)); | |
| 134 | + } else if (c == ';') { | |
| 135 | + break; | |
| 136 | + } else { | |
| 137 | + throw syntaxError("Missing ';' in XML entity: &" + sb); | |
| 138 | + } | |
| 139 | + } | |
| 140 | + String string = sb.toString(); | |
| 141 | + return unescapeEntity(string); | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Unescapes an XML entity encoding; | |
| 146 | + * @param e entity (only the actual entity value, not the preceding & or ending ; | |
| 147 | + * @return | |
| 148 | + */ | |
| 149 | + static String unescapeEntity(String e) { | |
| 150 | + // validate | |
| 151 | + if (e == null || e.isEmpty()) { | |
| 152 | + return ""; | |
| 153 | + } | |
| 154 | + // if our entity is an encoded unicode point, parse it. | |
| 155 | + if (e.charAt(0) == '#') { | |
| 156 | + int cp; | |
| 157 | + if (e.charAt(1) == 'x') { | |
| 158 | + // hex encoded unicode | |
| 159 | + cp = Integer.parseInt(e.substring(2), 16); | |
| 160 | + } else { | |
| 161 | + // decimal encoded unicode | |
| 162 | + cp = Integer.parseInt(e.substring(1)); | |
| 163 | + } | |
| 164 | + return new String(new int[] {cp},0,1); | |
| 165 | + } | |
| 166 | + Character knownEntity = entity.get(e); | |
| 167 | + if(knownEntity==null) { | |
| 168 | + // we don't know the entity so keep it encoded | |
| 169 | + return '&' + e + ';'; | |
| 170 | + } | |
| 171 | + return knownEntity.toString(); | |
| 172 | + } | |
| 173 | + | |
| 174 | + | |
| 175 | + /** | |
| 176 | + * Returns the next XML meta token. This is used for skipping over <!...> | |
| 177 | + * and <?...?> structures. | |
| 178 | + * @return Syntax characters (<code>< > / = ! ?</code>) are returned as | |
| 179 | + * Character, and strings and names are returned as Boolean. We don't care | |
| 180 | + * what the values actually are. | |
| 181 | + * @throws JSONException If a string is not properly closed or if the XML | |
| 182 | + * is badly structured. | |
| 183 | + */ | |
| 184 | + public Object nextMeta() throws JSONException { | |
| 185 | + char c; | |
| 186 | + char q; | |
| 187 | + do { | |
| 188 | + c = next(); | |
| 189 | + } while (Character.isWhitespace(c)); | |
| 190 | + switch (c) { | |
| 191 | + case 0: | |
| 192 | + throw syntaxError("Misshaped meta tag"); | |
| 193 | + case '<': | |
| 194 | + return XML.LT; | |
| 195 | + case '>': | |
| 196 | + return XML.GT; | |
| 197 | + case '/': | |
| 198 | + return XML.SLASH; | |
| 199 | + case '=': | |
| 200 | + return XML.EQ; | |
| 201 | + case '!': | |
| 202 | + return XML.BANG; | |
| 203 | + case '?': | |
| 204 | + return XML.QUEST; | |
| 205 | + case '"': | |
| 206 | + case '\'': | |
| 207 | + q = c; | |
| 208 | + for (;;) { | |
| 209 | + c = next(); | |
| 210 | + if (c == 0) { | |
| 211 | + throw syntaxError("Unterminated string"); | |
| 212 | + } | |
| 213 | + if (c == q) { | |
| 214 | + return Boolean.TRUE; | |
| 215 | + } | |
| 216 | + } | |
| 217 | + default: | |
| 218 | + for (;;) { | |
| 219 | + c = next(); | |
| 220 | + if (Character.isWhitespace(c)) { | |
| 221 | + return Boolean.TRUE; | |
| 222 | + } | |
| 223 | + switch (c) { | |
| 224 | + case 0: | |
| 225 | + case '<': | |
| 226 | + case '>': | |
| 227 | + case '/': | |
| 228 | + case '=': | |
| 229 | + case '!': | |
| 230 | + case '?': | |
| 231 | + case '"': | |
| 232 | + case '\'': | |
| 233 | + back(); | |
| 234 | + return Boolean.TRUE; | |
| 235 | + } | |
| 236 | + } | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + | |
| 241 | + /** | |
| 242 | + * Get the next XML TokenHolder. These tokens are found inside of angle | |
| 243 | + * brackets. It may be one of these characters: <code>/ > = ! ?</code> or it | |
| 244 | + * may be a string wrapped in single quotes or double quotes, or it may be a | |
| 245 | + * name. | |
| 246 | + * @return a String or a Character. | |
| 247 | + * @throws JSONException If the XML is not well formed. | |
| 248 | + */ | |
| 249 | + public Object nextToken() throws JSONException { | |
| 250 | + char c; | |
| 251 | + char q; | |
| 252 | + StringBuilder sb; | |
| 253 | + do { | |
| 254 | + c = next(); | |
| 255 | + } while (Character.isWhitespace(c)); | |
| 256 | + switch (c) { | |
| 257 | + case 0: | |
| 258 | + throw syntaxError("Misshaped element"); | |
| 259 | + case '<': | |
| 260 | + throw syntaxError("Misplaced '<'"); | |
| 261 | + case '>': | |
| 262 | + return XML.GT; | |
| 263 | + case '/': | |
| 264 | + return XML.SLASH; | |
| 265 | + case '=': | |
| 266 | + return XML.EQ; | |
| 267 | + case '!': | |
| 268 | + return XML.BANG; | |
| 269 | + case '?': | |
| 270 | + return XML.QUEST; | |
| 271 | + | |
| 272 | +// Quoted string | |
| 273 | + | |
| 274 | + case '"': | |
| 275 | + case '\'': | |
| 276 | + q = c; | |
| 277 | + sb = new StringBuilder(); | |
| 278 | + for (;;) { | |
| 279 | + c = next(); | |
| 280 | + if (c == 0) { | |
| 281 | + throw syntaxError("Unterminated string"); | |
| 282 | + } | |
| 283 | + if (c == q) { | |
| 284 | + return sb.toString(); | |
| 285 | + } | |
| 286 | + if (c == '&') { | |
| 287 | + sb.append(nextEntity(c)); | |
| 288 | + } else { | |
| 289 | + sb.append(c); | |
| 290 | + } | |
| 291 | + } | |
| 292 | + default: | |
| 293 | + | |
| 294 | +// Name | |
| 295 | + | |
| 296 | + sb = new StringBuilder(); | |
| 297 | + for (;;) { | |
| 298 | + sb.append(c); | |
| 299 | + c = next(); | |
| 300 | + if (Character.isWhitespace(c)) { | |
| 301 | + return sb.toString(); | |
| 302 | + } | |
| 303 | + switch (c) { | |
| 304 | + case 0: | |
| 305 | + return sb.toString(); | |
| 306 | + case '>': | |
| 307 | + case '/': | |
| 308 | + case '=': | |
| 309 | + case '!': | |
| 310 | + case '?': | |
| 311 | + case '[': | |
| 312 | + case ']': | |
| 313 | + back(); | |
| 314 | + return sb.toString(); | |
| 315 | + case '<': | |
| 316 | + case '"': | |
| 317 | + case '\'': | |
| 318 | + throw syntaxError("Bad character in a name"); | |
| 319 | + } | |
| 320 | + } | |
| 321 | + } | |
| 322 | + } | |
| 323 | + | |
| 324 | + | |
| 325 | + /** | |
| 326 | + * Skip characters until past the requested string. | |
| 327 | + * If it is not found, we are left at the end of the source with a result of false. | |
| 328 | + * @param to A string to skip past. | |
| 329 | + */ | |
| 330 | + // The Android implementation of JSONTokener has a public method of public void skipPast(String to) | |
| 331 | + // even though ours does not have that method, to have API compatibility, our method in the subclass | |
| 332 | + // should match. | |
| 333 | + public void skipPast(String to) { | |
| 334 | + boolean b; | |
| 335 | + char c; | |
| 336 | + int i; | |
| 337 | + int j; | |
| 338 | + int offset = 0; | |
| 339 | + int length = to.length(); | |
| 340 | + char[] circle = new char[length]; | |
| 341 | + | |
| 342 | + /* | |
| 343 | + * First fill the circle buffer with as many characters as are in the | |
| 344 | + * to string. If we reach an early end, bail. | |
| 345 | + */ | |
| 346 | + | |
| 347 | + for (i = 0; i < length; i += 1) { | |
| 348 | + c = next(); | |
| 349 | + if (c == 0) { | |
| 350 | + return; | |
| 351 | + } | |
| 352 | + circle[i] = c; | |
| 353 | + } | |
| 354 | + | |
| 355 | + /* We will loop, possibly for all of the remaining characters. */ | |
| 356 | + | |
| 357 | + for (;;) { | |
| 358 | + j = offset; | |
| 359 | + b = true; | |
| 360 | + | |
| 361 | + /* Compare the circle buffer with the to string. */ | |
| 362 | + | |
| 363 | + for (i = 0; i < length; i += 1) { | |
| 364 | + if (circle[j] != to.charAt(i)) { | |
| 365 | + b = false; | |
| 366 | + break; | |
| 367 | + } | |
| 368 | + j += 1; | |
| 369 | + if (j >= length) { | |
| 370 | + j -= length; | |
| 371 | + } | |
| 372 | + } | |
| 373 | + | |
| 374 | + /* If we exit the loop with b intact, then victory is ours. */ | |
| 375 | + | |
| 376 | + if (b) { | |
| 377 | + return; | |
| 378 | + } | |
| 379 | + | |
| 380 | + /* Get the next character. If there isn't one, then defeat is ours. */ | |
| 381 | + | |
| 382 | + c = next(); | |
| 383 | + if (c == 0) { | |
| 384 | + return; | |
| 385 | + } | |
| 386 | + /* | |
| 387 | + * Shove the character in the circle buffer and advance the | |
| 388 | + * circle offset. The offset is mod n. | |
| 389 | + */ | |
| 390 | + circle[offset] = c; | |
| 391 | + offset += 1; | |
| 392 | + if (offset >= length) { | |
| 393 | + offset -= length; | |
| 394 | + } | |
| 395 | + } | |
| 396 | + } | |
| 397 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/speech/restapi/asrdemo/AsrMain.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.speech.restapi.asrdemo; | |
| 2 | + | |
| 3 | +import com.bsth.data.zndd.baidu.org.json.JSONObject; | |
| 4 | +import com.bsth.data.zndd.baidu.speech.restapi.common.ConnUtil; | |
| 5 | +import com.bsth.data.zndd.baidu.speech.restapi.common.DemoException; | |
| 6 | +import com.bsth.data.zndd.baidu.speech.restapi.common.TokenHolder; | |
| 7 | +import com.bsth.entity.sys.SysUser; | |
| 8 | +import com.bsth.security.util.SecurityUtils; | |
| 9 | + | |
| 10 | +import java.io.File; | |
| 11 | +import java.io.FileInputStream; | |
| 12 | +import java.io.IOException; | |
| 13 | +import java.net.HttpURLConnection; | |
| 14 | +import java.net.URL; | |
| 15 | +import java.util.Base64; | |
| 16 | + | |
| 17 | +public class AsrMain { | |
| 18 | + | |
| 19 | + private final boolean METHOD_RAW = false; // 默认以json方式上传音频文件 | |
| 20 | + | |
| 21 | + // 填写网页上申请的appkey 如 $apiKey="g8eBUMSokVB1BHGmgxxxxxx" | |
| 22 | + private final String APP_KEY = "Oigm0L3Y8j78pDx6T5hFAmpD"; | |
| 23 | + | |
| 24 | + // 填写网页上申请的APP SECRET 如 $SECRET_KEY="94dc99566550d87f8fa8ece112xxxxx" | |
| 25 | + private final String SECRET_KEY = "v7OFLoPOqZBHn21VUHgTRUhFkFcXBxib"; | |
| 26 | + | |
| 27 | + //情感分析的 | |
| 28 | + private final String App_ID = "28015871"; | |
| 29 | + private final String API_Key = "FxxqPgNKzGoEA8NwR0jIuuoS"; | |
| 30 | + private final String Secret_Key = "ljnHGV5UyOcIO5UYKrCgGHPaxLDBh5El"; | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + private String CUID = "1234567JAVA"; | |
| 38 | + | |
| 39 | + // 采样率固定值 | |
| 40 | + private final int RATE = 16000; | |
| 41 | + | |
| 42 | + private String URL; | |
| 43 | + | |
| 44 | + private int DEV_PID; | |
| 45 | + | |
| 46 | + //private int LM_ID;//测试自训练平台需要打开此注释 | |
| 47 | + | |
| 48 | + private String SCOPE; | |
| 49 | + | |
| 50 | + // 普通版 参数 | |
| 51 | + { | |
| 52 | + URL = "http://vop.baidu.com/server_api"; // 可以改为https | |
| 53 | + // 1537 表示识别普通话,使用输入法模型。 其它语种参见文档 | |
| 54 | + DEV_PID = 1537; | |
| 55 | + SCOPE = "audio_voice_assistant_get"; | |
| 56 | + } | |
| 57 | + | |
| 58 | + // 自训练平台 参数 | |
| 59 | + /*{ | |
| 60 | + //自训练平台模型上线后,您会看见 第二步:“”获取专属模型参数pid:8001,modelid:1234”,按照这个信息获取 dev_pid=8001,lm_id=1234 | |
| 61 | + DEV_PID = 8001; | |
| 62 | + LM_ID = 1234; | |
| 63 | + }*/ | |
| 64 | + | |
| 65 | + /* 极速版 参数 | |
| 66 | + { | |
| 67 | + URL = "http://vop.baidu.com/pro_api"; // 可以改为https | |
| 68 | + DEV_PID = 80001; | |
| 69 | + SCOPE = "brain_enhanced_asr"; | |
| 70 | + } | |
| 71 | + */ | |
| 72 | + | |
| 73 | + /* 忽略scope检查,非常旧的应用可能没有 | |
| 74 | + { | |
| 75 | + SCOPE = null; | |
| 76 | + } | |
| 77 | + */ | |
| 78 | + | |
| 79 | + /*public static void main(String[] args) throws IOException, DemoException { | |
| 80 | + AsrMain demo = new AsrMain(); | |
| 81 | + // 填写下面信息 | |
| 82 | + String result = demo.run(); | |
| 83 | + System.out.println("识别结束:结果是:"); | |
| 84 | + | |
| 85 | + | |
| 86 | + System.out.println(result); | |
| 87 | + // 如果显示乱码,请打开result.txt查看 | |
| 88 | + File file = new File("result.txt"); | |
| 89 | + FileWriter fo = new FileWriter(file); | |
| 90 | + fo.write(result); | |
| 91 | + fo.close(); | |
| 92 | + System.out.println("Result also wrote into " + file.getAbsolutePath()); | |
| 93 | + }*/ | |
| 94 | + | |
| 95 | + | |
| 96 | + public String run() throws IOException, DemoException { | |
| 97 | + TokenHolder holder = new TokenHolder(APP_KEY, SECRET_KEY, SCOPE); | |
| 98 | + holder.resfresh(); | |
| 99 | + String token = holder.getToken(); | |
| 100 | + String result = null; | |
| 101 | + if (METHOD_RAW) { | |
| 102 | + result = runRawPostMethod(token); | |
| 103 | + } else { | |
| 104 | + result = runJsonPostMethod(token); | |
| 105 | + } | |
| 106 | + return result; | |
| 107 | + } | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + private String runRawPostMethod(String token) throws IOException, DemoException { | |
| 112 | + SysUser user = SecurityUtils.getCurrentUser(); | |
| 113 | + // 需要识别的文件 | |
| 114 | + String FILENAME = "/pcm/test_"+user.getUserName()+".wav"; | |
| 115 | + // 文件格式, 支持pcm/wav/amr 格式,极速版额外支持m4a 格式 | |
| 116 | + String FORMAT = FILENAME.substring(FILENAME.length() - 3); | |
| 117 | + String url2 = URL + "?cuid=" + ConnUtil.urlEncode(CUID) + "&dev_pid=" + DEV_PID + "&token=" + token; | |
| 118 | + //测试自训练平台需要打开以下信息 | |
| 119 | + //String url2 = URL + "?cuid=" + ConnUtil.urlEncode(CUID) + "&dev_pid=" + DEV_PID + "&lm_id="+ LM_ID + "&token=" + token; | |
| 120 | + String contentTypeStr = "audio/" + FORMAT + "; rate=" + RATE; | |
| 121 | + //System.out.println(url2); | |
| 122 | + byte[] content = getFileContent(FILENAME); | |
| 123 | + HttpURLConnection conn = (HttpURLConnection) new URL(url2).openConnection(); | |
| 124 | + conn.setConnectTimeout(5000); | |
| 125 | + conn.setRequestProperty("Content-Type", contentTypeStr); | |
| 126 | + conn.setRequestMethod("POST"); | |
| 127 | + conn.setDoOutput(true); | |
| 128 | + conn.getOutputStream().write(content); | |
| 129 | + conn.getOutputStream().close(); | |
| 130 | + //System.out.println("url is " + url2); | |
| 131 | + //System.out.println("header is " + "Content-Type :" + contentTypeStr); | |
| 132 | + String result = ConnUtil.getResponseString(conn); | |
| 133 | + return result; | |
| 134 | + } | |
| 135 | + | |
| 136 | + public String runJsonPostMethod(String token) throws DemoException, IOException { | |
| 137 | + SysUser user = SecurityUtils.getCurrentUser(); | |
| 138 | + // 需要识别的文件 | |
| 139 | + String FILENAME = "/pcm/test_"+user.getUserName()+".wav"; | |
| 140 | + // 文件格式, 支持pcm/wav/amr 格式,极速版额外支持m4a 格式 | |
| 141 | + String FORMAT = FILENAME.substring(FILENAME.length() - 3); | |
| 142 | + byte[] content = getFileContent(FILENAME); | |
| 143 | + String speech = base64Encode(content); | |
| 144 | + | |
| 145 | + JSONObject params = new JSONObject(); | |
| 146 | + params.put("dev_pid", DEV_PID); | |
| 147 | + //params.put("lm_id",LM_ID);//测试自训练平台需要打开注释 | |
| 148 | + params.put("format", FORMAT); | |
| 149 | + params.put("rate", RATE); | |
| 150 | + params.put("token", token); | |
| 151 | + params.put("cuid", CUID); | |
| 152 | + params.put("channel", "1"); | |
| 153 | + params.put("len", content.length); | |
| 154 | + params.put("speech", speech); | |
| 155 | + | |
| 156 | + // System.out.println(params.toString()); | |
| 157 | + HttpURLConnection conn = (HttpURLConnection) new URL(URL).openConnection(); | |
| 158 | + conn.setConnectTimeout(5000); | |
| 159 | + conn.setRequestMethod("POST"); | |
| 160 | + conn.setRequestProperty("Content-Type", "application/json; charset=utf-8"); | |
| 161 | + conn.setDoOutput(true); | |
| 162 | + conn.getOutputStream().write(params.toString().getBytes()); | |
| 163 | + conn.getOutputStream().close(); | |
| 164 | + String result = ConnUtil.getResponseString(conn); | |
| 165 | + | |
| 166 | + | |
| 167 | + params.put("speech", "base64Encode(getFileContent(FILENAME))"); | |
| 168 | + //System.out.println("url is : " + URL); | |
| 169 | + //System.out.println("params is :" + params.toString()); | |
| 170 | + | |
| 171 | + | |
| 172 | + return result; | |
| 173 | + } | |
| 174 | + | |
| 175 | + private byte[] getFileContent(String filename) throws DemoException, IOException { | |
| 176 | + File file = new File(filename); | |
| 177 | + if (!file.canRead()) { | |
| 178 | + System.err.println("文件不存在或者不可读: " + file.getAbsolutePath()); | |
| 179 | + throw new DemoException("file cannot read: " + file.getAbsolutePath()); | |
| 180 | + } | |
| 181 | + FileInputStream is = null; | |
| 182 | + try { | |
| 183 | + is = new FileInputStream(file); | |
| 184 | + return ConnUtil.getInputStreamContent(is); | |
| 185 | + } finally { | |
| 186 | + if (is != null) { | |
| 187 | + try { | |
| 188 | + is.close(); | |
| 189 | + } catch (IOException e) { | |
| 190 | + e.printStackTrace(); | |
| 191 | + } | |
| 192 | + } | |
| 193 | + } | |
| 194 | + | |
| 195 | + } | |
| 196 | + | |
| 197 | + private String base64Encode(byte[] content) { | |
| 198 | + | |
| 199 | + Base64.Encoder encoder = Base64.getEncoder(); // JDK 1.8 推荐方法 | |
| 200 | + String str = encoder.encodeToString(content); | |
| 201 | + | |
| 202 | + | |
| 203 | + /* char[] chars = Base64Util.encode(content); // 1.7 及以下,不推荐,请自行跟换相关库 | |
| 204 | + String str = new String(chars); | |
| 205 | +*/ | |
| 206 | + return str; | |
| 207 | + } | |
| 208 | + | |
| 209 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/speech/restapi/asrdemo/Base64Util.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.speech.restapi.asrdemo; | |
| 2 | + | |
| 3 | +import java.io.*; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Base64 编码和解码。 | |
| 7 | + * | |
| 8 | + * @author jiangshuai | |
| 9 | + * @date 2016年10月03日 | |
| 10 | + */ | |
| 11 | +public class Base64Util { | |
| 12 | + | |
| 13 | + public Base64Util() { | |
| 14 | + } | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 功能:编码字符串 | |
| 18 | + * | |
| 19 | + * @author jiangshuai | |
| 20 | + * @date 2016年10月03日 | |
| 21 | + * @param data | |
| 22 | + * 源字符串 | |
| 23 | + * @return String | |
| 24 | + */ | |
| 25 | + public static String encode(String data) { | |
| 26 | + return new String(encode(data.getBytes())); | |
| 27 | + } | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 功能:解码字符串 | |
| 31 | + * | |
| 32 | + * @author jiangshuai | |
| 33 | + * @date 2016年10月03日 | |
| 34 | + * @param data | |
| 35 | + * 源字符串 | |
| 36 | + * @return String | |
| 37 | + */ | |
| 38 | + public static String decode(String data) { | |
| 39 | + return new String(decode(data.toCharArray())); | |
| 40 | + } | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * 功能:编码byte[] | |
| 44 | + * | |
| 45 | + * @author jiangshuai | |
| 46 | + * @date 2016年10月03日 | |
| 47 | + * @param data | |
| 48 | + * 源 | |
| 49 | + * @return char[] | |
| 50 | + */ | |
| 51 | + public static char[] encode(byte[] data) { | |
| 52 | + char[] out = new char[((data.length + 2) / 3) * 4]; | |
| 53 | + for (int i = 0, index = 0; i < data.length; i += 3, index += 4) { | |
| 54 | + boolean quad = false; | |
| 55 | + boolean trip = false; | |
| 56 | + | |
| 57 | + int val = (0xFF & (int) data[i]); | |
| 58 | + val <<= 8; | |
| 59 | + if ((i + 1) < data.length) { | |
| 60 | + val |= (0xFF & (int) data[i + 1]); | |
| 61 | + trip = true; | |
| 62 | + } | |
| 63 | + val <<= 8; | |
| 64 | + if ((i + 2) < data.length) { | |
| 65 | + val |= (0xFF & (int) data[i + 2]); | |
| 66 | + quad = true; | |
| 67 | + } | |
| 68 | + out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)]; | |
| 69 | + val >>= 6; | |
| 70 | + out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)]; | |
| 71 | + val >>= 6; | |
| 72 | + out[index + 1] = alphabet[val & 0x3F]; | |
| 73 | + val >>= 6; | |
| 74 | + out[index + 0] = alphabet[val & 0x3F]; | |
| 75 | + } | |
| 76 | + return out; | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 功能:解码 | |
| 81 | + * | |
| 82 | + * @author jiangshuai | |
| 83 | + * @date 2016年10月03日 | |
| 84 | + * @param data | |
| 85 | + * 编码后的字符数组 | |
| 86 | + * @return byte[] | |
| 87 | + */ | |
| 88 | + public static byte[] decode(char[] data) { | |
| 89 | + | |
| 90 | + int tempLen = data.length; | |
| 91 | + for (int ix = 0; ix < data.length; ix++) { | |
| 92 | + if ((data[ix] > 255) || codes[data[ix]] < 0) { | |
| 93 | + --tempLen; // ignore non-valid chars and padding | |
| 94 | + } | |
| 95 | + } | |
| 96 | + // calculate required length: | |
| 97 | + // -- 3 bytes for every 4 valid base64 chars | |
| 98 | + // -- plus 2 bytes if there are 3 extra base64 chars, | |
| 99 | + // or plus 1 byte if there are 2 extra. | |
| 100 | + | |
| 101 | + int len = (tempLen / 4) * 3; | |
| 102 | + if ((tempLen % 4) == 3) { | |
| 103 | + len += 2; | |
| 104 | + } | |
| 105 | + if ((tempLen % 4) == 2) { | |
| 106 | + len += 1; | |
| 107 | + | |
| 108 | + } | |
| 109 | + byte[] out = new byte[len]; | |
| 110 | + | |
| 111 | + int shift = 0; // # of excess bits stored in accum | |
| 112 | + int accum = 0; // excess bits | |
| 113 | + int index = 0; | |
| 114 | + | |
| 115 | + // we now go through the entire array (NOT using the 'tempLen' value) | |
| 116 | + for (int ix = 0; ix < data.length; ix++) { | |
| 117 | + int value = (data[ix] > 255) ? -1 : codes[data[ix]]; | |
| 118 | + | |
| 119 | + if (value >= 0) { // skip over non-code | |
| 120 | + accum <<= 6; // bits shift up by 6 each time thru | |
| 121 | + shift += 6; // loop, with new bits being put in | |
| 122 | + accum |= value; // at the bottom. | |
| 123 | + if (shift >= 8) { // whenever there are 8 or more shifted in, | |
| 124 | + shift -= 8; // write them out (from the top, leaving any | |
| 125 | + out[index++] = // excess at the bottom for next iteration. | |
| 126 | + (byte) ((accum >> shift) & 0xff); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + } | |
| 130 | + | |
| 131 | + // if there is STILL something wrong we just have to throw up now! | |
| 132 | + if (index != out.length) { | |
| 133 | + throw new Error("Miscalculated data length (wrote " + index | |
| 134 | + + " instead of " + out.length + ")"); | |
| 135 | + } | |
| 136 | + | |
| 137 | + return out; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * 功能:编码文件 | |
| 142 | + * | |
| 143 | + * @author jiangshuai | |
| 144 | + * @date 2016年10月03日 | |
| 145 | + * @param file | |
| 146 | + * 源文件 | |
| 147 | + */ | |
| 148 | + public static void encode(File file) throws IOException { | |
| 149 | + if (!file.exists()) { | |
| 150 | + System.exit(0); | |
| 151 | + } | |
| 152 | + | |
| 153 | + else { | |
| 154 | + byte[] decoded = readBytes(file); | |
| 155 | + char[] encoded = encode(decoded); | |
| 156 | + writeChars(file, encoded); | |
| 157 | + } | |
| 158 | + file = null; | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * 功能:解码文件。 | |
| 163 | + * | |
| 164 | + * @author jiangshuai | |
| 165 | + * @date 2016年10月03日 | |
| 166 | + * @param file | |
| 167 | + * 源文件 | |
| 168 | + * @throws IOException | |
| 169 | + */ | |
| 170 | + public static void decode(File file) throws IOException { | |
| 171 | + if (!file.exists()) { | |
| 172 | + System.exit(0); | |
| 173 | + } else { | |
| 174 | + char[] encoded = readChars(file); | |
| 175 | + byte[] decoded = decode(encoded); | |
| 176 | + writeBytes(file, decoded); | |
| 177 | + } | |
| 178 | + file = null; | |
| 179 | + } | |
| 180 | + | |
| 181 | + // | |
| 182 | + // code characters for values 0..63 | |
| 183 | + // | |
| 184 | + private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" | |
| 185 | + .toCharArray(); | |
| 186 | + | |
| 187 | + // | |
| 188 | + // lookup table for converting base64 characters to value in range 0..63 | |
| 189 | + // | |
| 190 | + private static byte[] codes = new byte[256]; | |
| 191 | + static { | |
| 192 | + for (int i = 0; i < 256; i++) { | |
| 193 | + codes[i] = -1; | |
| 194 | + // LoggerUtil.debug(i + "&" + codes[i] + " "); | |
| 195 | + } | |
| 196 | + for (int i = 'A'; i <= 'Z'; i++) { | |
| 197 | + codes[i] = (byte) (i - 'A'); | |
| 198 | + // LoggerUtil.debug(i + "&" + codes[i] + " "); | |
| 199 | + } | |
| 200 | + | |
| 201 | + for (int i = 'a'; i <= 'z'; i++) { | |
| 202 | + codes[i] = (byte) (26 + i - 'a'); | |
| 203 | + // LoggerUtil.debug(i + "&" + codes[i] + " "); | |
| 204 | + } | |
| 205 | + for (int i = '0'; i <= '9'; i++) { | |
| 206 | + codes[i] = (byte) (52 + i - '0'); | |
| 207 | + // LoggerUtil.debug(i + "&" + codes[i] + " "); | |
| 208 | + } | |
| 209 | + codes['+'] = 62; | |
| 210 | + codes['/'] = 63; | |
| 211 | + } | |
| 212 | + | |
| 213 | + private static byte[] readBytes(File file) throws IOException { | |
| 214 | + ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| 215 | + byte[] b = null; | |
| 216 | + InputStream fis = null; | |
| 217 | + InputStream is = null; | |
| 218 | + try { | |
| 219 | + fis = new FileInputStream(file); | |
| 220 | + is = new BufferedInputStream(fis); | |
| 221 | + int count = 0; | |
| 222 | + byte[] buf = new byte[16384]; | |
| 223 | + while ((count = is.read(buf)) != -1) { | |
| 224 | + if (count > 0) { | |
| 225 | + baos.write(buf, 0, count); | |
| 226 | + } | |
| 227 | + } | |
| 228 | + b = baos.toByteArray(); | |
| 229 | + | |
| 230 | + } finally { | |
| 231 | + try { | |
| 232 | + if (fis != null) | |
| 233 | + fis.close(); | |
| 234 | + if (is != null) | |
| 235 | + is.close(); | |
| 236 | + if (baos != null) | |
| 237 | + baos.close(); | |
| 238 | + } catch (Exception e) { | |
| 239 | + System.out.println(e); | |
| 240 | + } | |
| 241 | + } | |
| 242 | + | |
| 243 | + return b; | |
| 244 | + } | |
| 245 | + | |
| 246 | + private static char[] readChars(File file) throws IOException { | |
| 247 | + CharArrayWriter caw = new CharArrayWriter(); | |
| 248 | + Reader fr = null; | |
| 249 | + Reader in = null; | |
| 250 | + try { | |
| 251 | + fr = new FileReader(file); | |
| 252 | + in = new BufferedReader(fr); | |
| 253 | + int count = 0; | |
| 254 | + char[] buf = new char[16384]; | |
| 255 | + while ((count = in.read(buf)) != -1) { | |
| 256 | + if (count > 0) { | |
| 257 | + caw.write(buf, 0, count); | |
| 258 | + } | |
| 259 | + } | |
| 260 | + | |
| 261 | + } finally { | |
| 262 | + try { | |
| 263 | + if (caw != null) | |
| 264 | + caw.close(); | |
| 265 | + if (in != null) | |
| 266 | + in.close(); | |
| 267 | + if (fr != null) | |
| 268 | + fr.close(); | |
| 269 | + } catch (Exception e) { | |
| 270 | + System.out.println(e); | |
| 271 | + } | |
| 272 | + } | |
| 273 | + | |
| 274 | + return caw.toCharArray(); | |
| 275 | + } | |
| 276 | + | |
| 277 | + private static void writeBytes(File file, byte[] data) throws IOException { | |
| 278 | + OutputStream fos = null; | |
| 279 | + OutputStream os = null; | |
| 280 | + try { | |
| 281 | + fos = new FileOutputStream(file); | |
| 282 | + os = new BufferedOutputStream(fos); | |
| 283 | + os.write(data); | |
| 284 | + | |
| 285 | + } finally { | |
| 286 | + try { | |
| 287 | + if (os != null) | |
| 288 | + os.close(); | |
| 289 | + if (fos != null) | |
| 290 | + fos.close(); | |
| 291 | + } catch (Exception e) { | |
| 292 | + System.out.println(e); | |
| 293 | + } | |
| 294 | + } | |
| 295 | + } | |
| 296 | + | |
| 297 | + private static void writeChars(File file, char[] data) throws IOException { | |
| 298 | + Writer fos = null; | |
| 299 | + Writer os = null; | |
| 300 | + try { | |
| 301 | + fos = new FileWriter(file); | |
| 302 | + os = new BufferedWriter(fos); | |
| 303 | + os.write(data); | |
| 304 | + | |
| 305 | + } finally { | |
| 306 | + try { | |
| 307 | + if (os != null) | |
| 308 | + os.close(); | |
| 309 | + if (fos != null) | |
| 310 | + fos.close(); | |
| 311 | + } catch (Exception e) { | |
| 312 | + e.printStackTrace(); | |
| 313 | + } | |
| 314 | + } | |
| 315 | + } | |
| 316 | + | |
| 317 | + // ///////////////////////////////////////////////// | |
| 318 | + // end of test code. | |
| 319 | + // ///////////////////////////////////////////////// | |
| 320 | + | |
| 321 | +} | |
| 0 | 322 | \ No newline at end of file | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/speech/restapi/common/ConnUtil.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.speech.restapi.common; | |
| 2 | + | |
| 3 | +import java.io.ByteArrayOutputStream; | |
| 4 | +import java.io.IOException; | |
| 5 | +import java.io.InputStream; | |
| 6 | +import java.io.UnsupportedEncodingException; | |
| 7 | +import java.net.HttpURLConnection; | |
| 8 | +import java.net.URLEncoder; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * 与连接相关的Util类 | |
| 12 | + */ | |
| 13 | +public class ConnUtil { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * UrlEncode, UTF-8 编码 | |
| 17 | + * | |
| 18 | + * @param str 原始字符串 | |
| 19 | + * @return | |
| 20 | + */ | |
| 21 | + public static String urlEncode(String str) { | |
| 22 | + String result = null; | |
| 23 | + try { | |
| 24 | + result = URLEncoder.encode(str, "UTF-8"); | |
| 25 | + } catch (UnsupportedEncodingException e) { | |
| 26 | + e.printStackTrace(); | |
| 27 | + } | |
| 28 | + return result; | |
| 29 | + } | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 从HttpURLConnection 获取返回的字符串 | |
| 33 | + * | |
| 34 | + * @param conn | |
| 35 | + * @return | |
| 36 | + * @throws IOException | |
| 37 | + * @throws DemoException | |
| 38 | + */ | |
| 39 | + public static String getResponseString(HttpURLConnection conn) throws IOException, DemoException { | |
| 40 | + return new String(getResponseBytes(conn)); | |
| 41 | + } | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 从HttpURLConnection 获取返回的bytes | |
| 45 | + * 注意 HttpURLConnection自身问题, 400类错误,会直接抛出异常。不能获取conn.getInputStream(); | |
| 46 | + * | |
| 47 | + * @param conn | |
| 48 | + * @return | |
| 49 | + * @throws IOException http请求错误 | |
| 50 | + * @throws DemoException http 的状态码不是 200 | |
| 51 | + */ | |
| 52 | + public static byte[] getResponseBytes(HttpURLConnection conn) throws IOException, DemoException { | |
| 53 | + int responseCode = conn.getResponseCode(); | |
| 54 | + InputStream inputStream = conn.getInputStream(); | |
| 55 | + if (responseCode != 200) { | |
| 56 | + System.err.println("http 请求返回的状态码错误,期望200, 当前是 " + responseCode); | |
| 57 | + if (responseCode == 401) { | |
| 58 | + System.err.println("可能是appkey appSecret 填错"); | |
| 59 | + } | |
| 60 | + System.err.println("response headers" + conn.getHeaderFields()); | |
| 61 | + if (inputStream == null) { | |
| 62 | + inputStream = conn.getErrorStream(); | |
| 63 | + } | |
| 64 | + byte[] result = getInputStreamContent(inputStream); | |
| 65 | + System.err.println(new String(result)); | |
| 66 | + | |
| 67 | + throw new DemoException("http response code is" + responseCode); | |
| 68 | + } | |
| 69 | + | |
| 70 | + byte[] result = getInputStreamContent(inputStream); | |
| 71 | + return result; | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * 将InputStream内的内容全部读取,作为bytes返回 | |
| 76 | + * | |
| 77 | + * @param is | |
| 78 | + * @return | |
| 79 | + * @throws IOException @see InputStream.read() | |
| 80 | + */ | |
| 81 | + public static byte[] getInputStreamContent(InputStream is) throws IOException { | |
| 82 | + byte[] b = new byte[1024]; | |
| 83 | + // 定义一个输出流存储接收到的数据 | |
| 84 | + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | |
| 85 | + // 开始接收数据 | |
| 86 | + int len = 0; | |
| 87 | + while (true) { | |
| 88 | + len = is.read(b); | |
| 89 | + if (len == -1) { | |
| 90 | + // 数据读完 | |
| 91 | + break; | |
| 92 | + } | |
| 93 | + byteArrayOutputStream.write(b, 0, len); | |
| 94 | + } | |
| 95 | + return byteArrayOutputStream.toByteArray(); | |
| 96 | + } | |
| 97 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/baidu/speech/restapi/common/DemoException.java
0 → 100644
src/main/java/com/bsth/data/zndd/baidu/speech/restapi/common/TokenHolder.java
0 → 100644
| 1 | +package com.bsth.data.zndd.baidu.speech.restapi.common; | |
| 2 | + | |
| 3 | +import com.bsth.data.zndd.baidu.org.json.JSONObject; | |
| 4 | + | |
| 5 | +import java.io.IOException; | |
| 6 | +import java.net.HttpURLConnection; | |
| 7 | +import java.net.URL; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * token的获取类 | |
| 11 | + * 将apiKey和secretKey换取token,注意有效期保存在expiresAt | |
| 12 | + */ | |
| 13 | +public class TokenHolder { | |
| 14 | + | |
| 15 | + | |
| 16 | + public static final String TTS_SCOPE = "audio_tts_post"; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * url , Token的url,http可以改为https | |
| 20 | + */ | |
| 21 | + private static final String url = "http://aip.baidubce.com/oauth/2.0/token"; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * asr的权限 scope 是 "audio_voice_assistant_get" | |
| 25 | + * tts 的权限 scope 是 "audio_tts_post" | |
| 26 | + */ | |
| 27 | + private String scope; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 网页上申请语音识别应用获取的apiKey | |
| 31 | + */ | |
| 32 | + private String apiKey; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 网页上申请语音识别应用获取的secretKey | |
| 36 | + */ | |
| 37 | + private String secretKey; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 保存访问接口获取的token | |
| 41 | + */ | |
| 42 | + private String token; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 当前的时间戳,毫秒 | |
| 46 | + */ | |
| 47 | + private long expiresAt; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * @param apiKey 网页上申请语音识别应用获取的apiKey | |
| 51 | + * @param secretKey 网页上申请语音识别应用获取的secretKey | |
| 52 | + */ | |
| 53 | + public TokenHolder(String apiKey, String secretKey, String scope) { | |
| 54 | + this.apiKey = apiKey; | |
| 55 | + this.secretKey = secretKey; | |
| 56 | + this.scope = scope; | |
| 57 | + } | |
| 58 | + | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * 获取token,refresh 方法后调用有效 | |
| 62 | + * | |
| 63 | + * @return | |
| 64 | + */ | |
| 65 | + public String getToken() { | |
| 66 | + return token; | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 获取过期时间,refresh 方法后调用有效 | |
| 71 | + * | |
| 72 | + * @return | |
| 73 | + */ | |
| 74 | + public long getExpiresAt() { | |
| 75 | + return expiresAt; | |
| 76 | + } | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * 获取token | |
| 83 | + * | |
| 84 | + * @return | |
| 85 | + * @throws IOException http请求错误 | |
| 86 | + * @throws DemoException http接口返回不是 200, access_token未获取 | |
| 87 | + */ | |
| 88 | + public void resfresh() throws IOException, DemoException { | |
| 89 | + String getTokenURL = url + "?grant_type=client_credentials" | |
| 90 | + + "&client_id=" + ConnUtil.urlEncode(apiKey) + "&client_secret=" + ConnUtil.urlEncode(secretKey); | |
| 91 | + | |
| 92 | + // 打印的url出来放到浏览器内可以复现 | |
| 93 | + System.out.println("token url:" + getTokenURL); | |
| 94 | + | |
| 95 | + URL url = new URL(getTokenURL); | |
| 96 | + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | |
| 97 | + conn.setConnectTimeout(5000); | |
| 98 | + String result = ConnUtil.getResponseString(conn); | |
| 99 | + System.out.println("Token result json:" + result); | |
| 100 | + parseJson(result); | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * @param result token接口获得的result | |
| 105 | + * @throws DemoException | |
| 106 | + */ | |
| 107 | + private void parseJson(String result) throws DemoException { | |
| 108 | + JSONObject json = new JSONObject(result); | |
| 109 | + if (!json.has("access_token")) { | |
| 110 | + // 返回没有access_token字段 | |
| 111 | + throw new DemoException("access_token not obtained, " + result); | |
| 112 | + } | |
| 113 | + if (!json.has("scope")) { | |
| 114 | + // 返回没有scope字段 | |
| 115 | + throw new DemoException("scopenot obtained, " + result); | |
| 116 | + } | |
| 117 | + token = json.getString("access_token"); | |
| 118 | + expiresAt = System.currentTimeMillis() + json.getLong("expires_in") * 1000; | |
| 119 | + } | |
| 120 | +} | ... | ... |
src/main/java/com/bsth/data/zndd/voice/UploadVideoServlet.java
0 → 100644
| 1 | +package com.bsth.data.zndd.voice; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.bsth.data.BasicData; | |
| 5 | +import com.bsth.data.zndd.baidu.speech.restapi.asrdemo.AsrMain; | |
| 6 | +import com.bsth.entity.StationRoute; | |
| 7 | +import com.bsth.entity.sys.SysUser; | |
| 8 | +import com.bsth.security.util.SecurityUtils; | |
| 9 | +import com.bsth.service.StationRouteService; | |
| 10 | +import net.sourceforge.pinyin4j.PinyinHelper; | |
| 11 | +import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; | |
| 12 | +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; | |
| 13 | +import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; | |
| 14 | +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; | |
| 15 | +import org.apache.commons.fileupload.disk.DiskFileItemFactory; | |
| 16 | +import org.apache.commons.fileupload.servlet.ServletFileUpload; | |
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 18 | +import org.springframework.stereotype.Service; | |
| 19 | +import org.springframework.web.multipart.MultipartFile; | |
| 20 | +import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest; | |
| 21 | + | |
| 22 | +import javax.servlet.ServletException; | |
| 23 | +import javax.servlet.http.HttpServlet; | |
| 24 | +import javax.servlet.http.HttpServletRequest; | |
| 25 | +import javax.servlet.http.HttpServletResponse; | |
| 26 | +import java.io.*; | |
| 27 | +import java.util.*; | |
| 28 | +import java.util.regex.Matcher; | |
| 29 | +import java.util.regex.Pattern; | |
| 30 | + | |
| 31 | + | |
| 32 | +@Service | |
| 33 | +public class UploadVideoServlet extends HttpServlet { | |
| 34 | + | |
| 35 | + @Autowired | |
| 36 | + StationRouteService stationRouteService; | |
| 37 | + | |
| 38 | + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
| 39 | + System.out.println("1"); | |
| 40 | + | |
| 41 | + } | |
| 42 | + | |
| 43 | + //如果出现多线程的情况下 识别文件名称可以加上专属账号的属性 | |
| 44 | + public void doPost(String line,HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
| 45 | + // 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全 | |
| 46 | + String savePath = "/pcm"; | |
| 47 | + | |
| 48 | + File file = new File(savePath); | |
| 49 | + // 判断上传文件的保存目录是否存在 | |
| 50 | + if (!file.exists() && !file.isDirectory()) { | |
| 51 | + System.out.println(savePath + "目录不存在,需要创建"); | |
| 52 | + // 创建目录 | |
| 53 | + file.mkdir(); | |
| 54 | + } | |
| 55 | + // 消息提示 | |
| 56 | + String message = ""; | |
| 57 | + try { | |
| 58 | + String filename = null; | |
| 59 | + // 使用Apache文件上传组件处理文件上传步骤: | |
| 60 | + // 1、创建一个DiskFileItemFactory工厂 | |
| 61 | + DiskFileItemFactory factory = new DiskFileItemFactory(); | |
| 62 | + // 2、创建一个文件上传解析器 | |
| 63 | + ServletFileUpload upload = new ServletFileUpload(factory); | |
| 64 | + // 解决上传文件名的中文乱码 | |
| 65 | + upload.setHeaderEncoding("UTF-8"); | |
| 66 | + // 3、判断提交上来的数据是否是上传表单的数据 | |
| 67 | + if (!ServletFileUpload.isMultipartContent(request)) { | |
| 68 | + // 按照传统方式获取数据 | |
| 69 | + return; | |
| 70 | + } | |
| 71 | + StandardMultipartHttpServletRequest req = (StandardMultipartHttpServletRequest) request; | |
| 72 | + Iterator<String> iterator = req.getFileNames(); | |
| 73 | + | |
| 74 | + String[] value = new String[5]; | |
| 75 | + int i = 0; | |
| 76 | + while (iterator.hasNext()) { | |
| 77 | + MultipartFile item = req.getFile(iterator.next()); | |
| 78 | + SysUser user = SecurityUtils.getCurrentUser(); | |
| 79 | + // 如果fileitem中封装的是上传文件 | |
| 80 | + // 得到上传的文件名称, | |
| 81 | + filename = "test_"+user.getUserName()+".wav"; | |
| 82 | + //item.getName(); | |
| 83 | + //System.out.println(filename); | |
| 84 | + | |
| 85 | + // 获取item中的上传文件的输入流 | |
| 86 | + InputStream in = item.getInputStream(); | |
| 87 | + // 创建一个文件输出流 | |
| 88 | + FileOutputStream out = new FileOutputStream(savePath + "/" + filename); | |
| 89 | + // 创建一个缓冲区 | |
| 90 | + byte buffer[] = new byte[1024]; | |
| 91 | + // 判断输入流中的数据是否已经读完的标识 | |
| 92 | + int len = 0; | |
| 93 | + // 循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 | |
| 94 | + while ((len = in.read(buffer)) > 0) { | |
| 95 | + // 使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" | |
| 96 | + // + filename)当中 | |
| 97 | + out.write(buffer, 0, len); | |
| 98 | + } | |
| 99 | + // 关闭输入流 | |
| 100 | + in.close(); | |
| 101 | + // 关闭输出流 | |
| 102 | + out.close(); | |
| 103 | + // 删除处理文件上传时生成的临时文件 | |
| 104 | + //item.delete(); | |
| 105 | + message = "文件上传成功!"; | |
| 106 | + //System.out.println(message); | |
| 107 | + /*VoiceUtil voiceUtil= new VoiceUtil(); | |
| 108 | + String str = voiceUtil.getWord(savePath + "/" + filename); | |
| 109 | + str = str.replace(" ","");*/ | |
| 110 | + //语音转文字 | |
| 111 | + AsrMain demo = new AsrMain(); | |
| 112 | + // 填写下面信息 | |
| 113 | + String result = demo.run(); | |
| 114 | + JSONObject json = JSONObject.parseObject(result); | |
| 115 | + List textList = ( List)json.get("result"); | |
| 116 | + String str = textList.get(0).toString().replace("。",""); | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + System.out.println("语音解析:"+str); | |
| 121 | + //定义输出类型 | |
| 122 | + response.setHeader("Content-type", "text/html;charset=UTF-8"); | |
| 123 | + PrintWriter writer = response.getWriter(); | |
| 124 | + List<retun> list1 = new ArrayList<>(); | |
| 125 | + String text = textList.get(0).toString(); | |
| 126 | + | |
| 127 | + | |
| 128 | + //帮我添加一个夏硕路林兰路到鸿音路云端路的班次 | |
| 129 | + String fcsj = null;//线路名,上下行,发车时间 | |
| 130 | + String[] ks = text.replace(",","").split("到"); | |
| 131 | + String Station1= ks[0].split("个")[1]; | |
| 132 | + String Station2= ks[1].split("的")[0]; | |
| 133 | + //发车时间 | |
| 134 | + fcsj = extractTimes(text); | |
| 135 | + //线路名称 - 线路编码和名称对照 | |
| 136 | + | |
| 137 | + Map<String, Object> param = new HashMap<>(); | |
| 138 | + param.put("lineCode_eq", line); | |
| 139 | + param.put("directions_eq", 0); | |
| 140 | + param.put("destroy_eq", 0); | |
| 141 | + List<StationRoute> stationup = ((List<StationRoute>) stationRouteService.list(param)); | |
| 142 | + //上行匹配 | |
| 143 | + Map m = pyPp(stationup,Station1,Station2); | |
| 144 | + if (m.get("stationcode1") == null || m.get("stationcode2") == null){ | |
| 145 | + param.put("directions_eq",1); | |
| 146 | + List<StationRoute> stationdown = ((List<StationRoute>) stationRouteService.list(param)); | |
| 147 | + //下行匹配 | |
| 148 | + Map smap = pyPp(stationdown,Station1,Station2); | |
| 149 | + if (smap.get("stationcode1") == null || smap.get("stationcode2") == null){ | |
| 150 | + writer.write(text +","+"99999"); | |
| 151 | + return; | |
| 152 | + } | |
| 153 | + | |
| 154 | + writer.write(text +","+smap.get("stationcode1")+","+smap.get("stationcode2")+","+1); | |
| 155 | + return; | |
| 156 | + } | |
| 157 | + | |
| 158 | + writer.write(text +","+m.get("stationcode1")+","+m.get("stationcode2")+","+0); | |
| 159 | + return; | |
| 160 | + | |
| 161 | + //打开0 关闭1 临加2 999异常 | |
| 162 | + } | |
| 163 | + | |
| 164 | + } catch (Exception e) { | |
| 165 | + message = "文件上传失败!"; | |
| 166 | + System.out.println(message); | |
| 167 | + e.printStackTrace(); | |
| 168 | + } | |
| 169 | + | |
| 170 | + } | |
| 171 | + | |
| 172 | + public static Map pyPp(List<StationRoute> stationss,String Station1,String Station2){ | |
| 173 | + | |
| 174 | + Double sity1 = 0D,sity2 = 0D; //拼音匹配百分比 | |
| 175 | + Map m = new HashMap(); | |
| 176 | + String stationcode1 = null,stationcode2 = null;//匹配的站点 | |
| 177 | + Boolean st2 = false; | |
| 178 | + for (StationRoute st : stationss){ | |
| 179 | + sity1 = calculateSimilarity(st.getStationName(), Station1); | |
| 180 | + if (sity1 >= 0.75 && !st2){ | |
| 181 | + stationcode1 = st.getStationCode(); | |
| 182 | + st2 =true; | |
| 183 | + } | |
| 184 | + | |
| 185 | + if (st2){ | |
| 186 | + sity2 = calculateSimilarity(st.getStationName(), Station2); | |
| 187 | + if(sity2 >= 0.75){ | |
| 188 | + stationcode2 = st.getStationCode(); | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + } | |
| 193 | + m.put("stationcode1",stationcode1); | |
| 194 | + m.put("stationcode2",stationcode2); | |
| 195 | + | |
| 196 | + return m; | |
| 197 | + } | |
| 198 | + | |
| 199 | + | |
| 200 | + private static final Pattern TIME_PATTERN = | |
| 201 | + Pattern.compile("([0-5][0-9]:[0-5][0-9])"); | |
| 202 | + //获取添加班次时间 | |
| 203 | + public static String extractTimes(String text) { | |
| 204 | + Matcher matcher = TIME_PATTERN.matcher(text); | |
| 205 | + while (matcher.find()) { | |
| 206 | + return matcher.group(); | |
| 207 | + } | |
| 208 | + return ""; | |
| 209 | + } | |
| 210 | + | |
| 211 | + | |
| 212 | + class retun { | |
| 213 | + private String tite; | |
| 214 | + private String txt; | |
| 215 | + | |
| 216 | + | |
| 217 | + public String getTite() { | |
| 218 | + return tite; | |
| 219 | + } | |
| 220 | + | |
| 221 | + public void setTite(String tite) { | |
| 222 | + this.tite = tite; | |
| 223 | + } | |
| 224 | + | |
| 225 | + public String getTxt() { | |
| 226 | + return txt; | |
| 227 | + } | |
| 228 | + | |
| 229 | + public void setTxt(String txt) { | |
| 230 | + this.txt = txt; | |
| 231 | + } | |
| 232 | + } | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + public static String getPinyin(String chinese) { | |
| 237 | + HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); | |
| 238 | + format.setCaseType(HanyuPinyinCaseType.LOWERCASE); | |
| 239 | + format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); | |
| 240 | + | |
| 241 | + StringBuilder pinyinBuilder = new StringBuilder(); | |
| 242 | + char[] charArray = chinese.toCharArray(); | |
| 243 | + for (char c : charArray) { | |
| 244 | + String[] pinyinArray = null; | |
| 245 | + try { | |
| 246 | + pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format); | |
| 247 | + } catch (BadHanyuPinyinOutputFormatCombination e) { | |
| 248 | + e.printStackTrace(); | |
| 249 | + } | |
| 250 | + if (pinyinArray != null) { | |
| 251 | + pinyinBuilder.append(pinyinArray[0]); | |
| 252 | + } else { | |
| 253 | + pinyinBuilder.append(c); | |
| 254 | + } | |
| 255 | + } | |
| 256 | + return pinyinBuilder.toString(); | |
| 257 | + } | |
| 258 | + | |
| 259 | + public static Double calculateSimilarity(String str1, String str2) { | |
| 260 | + String pinyinStr1 = getPinyin(str1); | |
| 261 | + String pinyinStr2 = getPinyin(str2); | |
| 262 | + | |
| 263 | + int len1 = pinyinStr1.length(); | |
| 264 | + int len2 = pinyinStr2.length(); | |
| 265 | + int[][] dp = new int[len1 + 1][len2 + 1]; | |
| 266 | + | |
| 267 | + for (int i = 0; i <= len1; i++) { | |
| 268 | + dp[i][0] = 0; | |
| 269 | + } | |
| 270 | + for (int j = 0; j <= len2; j++) { | |
| 271 | + dp[0][j] = 0; | |
| 272 | + } | |
| 273 | + | |
| 274 | + for (int i = 1; i <= len1; i++) { | |
| 275 | + for (int j = 1; j <= len2; j++) { | |
| 276 | + if (pinyinStr1.charAt(i - 1) == pinyinStr2.charAt(j - 1)) { | |
| 277 | + dp[i][j] = dp[i - 1][j - 1] + 1; | |
| 278 | + } else { | |
| 279 | + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); | |
| 280 | + } | |
| 281 | + } | |
| 282 | + } | |
| 283 | + return Double.valueOf(dp[len1][len2]) / len1; | |
| 284 | + } | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | +} | |
| 0 | 292 | \ No newline at end of file | ... | ... |
src/main/java/com/bsth/data/zndd/voice/VoiceUtil.java
0 → 100644
| 1 | +package com.bsth.data.zndd.voice; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSON; | |
| 4 | +import com.alibaba.fastjson.JSONObject; | |
| 5 | +import com.sun.media.sound.WaveFileReader; | |
| 6 | +import com.sun.media.sound.WaveFileWriter; | |
| 7 | +import org.slf4j.Logger; | |
| 8 | +import org.slf4j.LoggerFactory; | |
| 9 | +import org.springframework.util.Assert; | |
| 10 | +import org.springframework.util.StringUtils; | |
| 11 | +import org.vosk.LibVosk; | |
| 12 | +import org.vosk.LogLevel; | |
| 13 | +import org.vosk.Model; | |
| 14 | +import org.vosk.Recognizer; | |
| 15 | + | |
| 16 | +import javax.sound.sampled.*; | |
| 17 | +import java.io.*; | |
| 18 | +import java.nio.file.Files; | |
| 19 | +import java.nio.file.Paths; | |
| 20 | + | |
| 21 | +public class VoiceUtil { | |
| 22 | + /* @Value("${leenleda.vosk.model}") | |
| 23 | + private String VOSKMODELPATH;*/ | |
| 24 | + | |
| 25 | + Logger log = LoggerFactory.getLogger(this.getClass()); | |
| 26 | + public String getWord(String filePath) throws IOException, UnsupportedAudioFileException { | |
| 27 | + Assert.isTrue(StringUtils.hasLength("D:\\pcm\\vosk-model-small-cn-0.22"), "无效的VOS模块!"); | |
| 28 | + byte[] bytes = Files.readAllBytes(Paths.get(filePath)); | |
| 29 | + // 转换为16KHZ | |
| 30 | + reSamplingAndSave(bytes, filePath); | |
| 31 | + File f = new File(filePath); | |
| 32 | + RandomAccessFile rdf = null; | |
| 33 | + rdf = new RandomAccessFile(f, "r"); | |
| 34 | + log.info("声音尺寸:{}", toInt(read(rdf, 4, 4))); | |
| 35 | + log.info("音频格式:{}", toShort(read(rdf, 20, 2))); | |
| 36 | + short track = toShort(read(rdf, 22, 2)); | |
| 37 | + log.info("1 单声道 2 双声道: {}", track); | |
| 38 | + log.info("采样率、音频采样级别 16000 = 16KHz: {}", toInt(read(rdf, 24, 4))); | |
| 39 | + log.info("每秒波形的数据量:{}", toShort(read(rdf, 22, 2))); | |
| 40 | + log.info("采样帧的大小:{}", toShort(read(rdf, 32, 2))); | |
| 41 | + log.info("采样位数:{}", toShort(read(rdf, 34, 2))); | |
| 42 | + rdf.close(); | |
| 43 | + LibVosk.setLogLevel(LogLevel.WARNINGS); | |
| 44 | + try ( | |
| 45 | + Model model = new Model("D:\\pcm\\vosk-model-small-cn-0.22"); | |
| 46 | + InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(filePath))); | |
| 47 | + // 采样率为音频采样率的声道倍数 | |
| 48 | + Recognizer recognizer = new Recognizer(model, 16000 * track)) { | |
| 49 | + | |
| 50 | + recognizer.setWords(true); | |
| 51 | + | |
| 52 | + String result = recognizer.getFinalResult(); | |
| 53 | + log.info("识别结果:{}", result); | |
| 54 | + if (StringUtils.hasLength(result)) { | |
| 55 | + JSONObject jsonObject = JSON.parseObject(result); | |
| 56 | + return jsonObject.getString("text").replace(" ", ""); | |
| 57 | + } | |
| 58 | + return ""; | |
| 59 | + } | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + } | |
| 64 | + | |
| 65 | + public static int toInt(byte[] b) { | |
| 66 | + return (((b[3] & 0xff) << 24) + ((b[2] & 0xff) << 16) + ((b[1] & 0xff) << 8) + ((b[0] & 0xff) << 0)); | |
| 67 | + } | |
| 68 | + | |
| 69 | + public static short toShort(byte[] b) { | |
| 70 | + return (short) ((b[1] << 8) + (b[0] << 0)); | |
| 71 | + } | |
| 72 | + | |
| 73 | + public static byte[] read(RandomAccessFile rdf, int pos, int length) throws IOException { | |
| 74 | + rdf.seek(pos); | |
| 75 | + byte result[] = new byte[length]; | |
| 76 | + for (int i = 0; i < length; i++) { | |
| 77 | + result[i] = rdf.readByte(); | |
| 78 | + } | |
| 79 | + return result; | |
| 80 | + } | |
| 81 | + | |
| 82 | + public static void reSamplingAndSave(byte[] data, String path) throws IOException, UnsupportedAudioFileException { | |
| 83 | + WaveFileReader reader = new WaveFileReader(); | |
| 84 | + AudioInputStream audioIn = reader.getAudioInputStream(new ByteArrayInputStream(data)); | |
| 85 | + AudioFormat srcFormat = audioIn.getFormat(); | |
| 86 | + int targetSampleRate = 16000; | |
| 87 | + AudioFormat dstFormat = new AudioFormat(srcFormat.getEncoding(), | |
| 88 | + targetSampleRate, | |
| 89 | + srcFormat.getSampleSizeInBits(), | |
| 90 | + srcFormat.getChannels(), | |
| 91 | + srcFormat.getFrameSize(), | |
| 92 | + srcFormat.getFrameRate(), | |
| 93 | + srcFormat.isBigEndian()); | |
| 94 | + AudioInputStream convertedIn = AudioSystem.getAudioInputStream(dstFormat, audioIn); | |
| 95 | + File file = new File(path); | |
| 96 | + WaveFileWriter writer = new WaveFileWriter(); | |
| 97 | + writer.write(convertedIn, AudioFileFormat.Type.WAVE, file); | |
| 98 | + } | |
| 99 | +} | |
| 0 | 100 | \ No newline at end of file | ... | ... |
src/main/java/com/bsth/service/zndd/LoggerZnddService.java
| 1 | 1 | package com.bsth.service.zndd; |
| 2 | 2 | |
| 3 | +import com.bsth.entity.realcontrol.ScheduleRealInfo; | |
| 3 | 4 | import com.bsth.entity.zndd.LoggerZndd; |
| 4 | 5 | import com.bsth.service.BaseService; |
| 5 | 6 | |
| ... | ... | @@ -10,4 +11,6 @@ public interface LoggerZnddService extends BaseService<LoggerZndd, Integer> { |
| 10 | 11 | |
| 11 | 12 | |
| 12 | 13 | List<Map<String, Object>> listAll(Map<String, Object> map); |
| 14 | + | |
| 15 | + public ScheduleRealInfo schlist(String lineCode,Integer dir); | |
| 13 | 16 | } | ... | ... |
src/main/java/com/bsth/service/zndd/impl/LoggerZnddServiceImpl.java
| 1 | 1 | package com.bsth.service.zndd.impl; |
| 2 | 2 | |
| 3 | +import com.bsth.data.schedule.DayOfSchedule; | |
| 4 | +import com.bsth.entity.realcontrol.ScheduleRealInfo; | |
| 3 | 5 | import com.bsth.entity.search.CustomerSpecs; |
| 4 | 6 | import com.bsth.entity.zndd.LoggerZndd; |
| 5 | 7 | import com.bsth.repository.zndd.LoggerZnddRepository; |
| ... | ... | @@ -20,9 +22,25 @@ public class LoggerZnddServiceImpl extends BaseServiceImpl<LoggerZndd, Integer> |
| 20 | 22 | |
| 21 | 23 | @Autowired |
| 22 | 24 | LoggerZnddRepository loggerZnddRepository; |
| 25 | + @Autowired | |
| 26 | + DayOfSchedule dayOfSchedule; | |
| 23 | 27 | public List<Map<String, Object>> listAll(Map<String, Object> map){ |
| 24 | 28 | loggerZnddRepository.findAll((Sort) map); |
| 25 | 29 | |
| 26 | 30 | return null; |
| 27 | 31 | } |
| 32 | + | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public ScheduleRealInfo schlist(String lineCode,Integer dir){ | |
| 36 | + List<ScheduleRealInfo> list = dayOfSchedule.findByLineAndUpDown(lineCode,dir); | |
| 37 | + if (!list.isEmpty() ){ | |
| 38 | + for (ScheduleRealInfo sr : list){ | |
| 39 | + if(sr.getBcType().equals("normal")){ | |
| 40 | + return sr; | |
| 41 | + } | |
| 42 | + } | |
| 43 | + } | |
| 44 | + return null; | |
| 45 | + }; | |
| 28 | 46 | } | ... | ... |
src/main/resources/fatso/package.json
src/main/resources/static/real_control_v2/css/main.css
| ... | ... | @@ -2243,4 +2243,15 @@ g.gps-wrap rect.twinkle[updown="1"] { |
| 2243 | 2243 | color: white; |
| 2244 | 2244 | text-align: center; |
| 2245 | 2245 | margin-top: 5px; |
| 2246 | +} | |
| 2247 | +#recidress{ | |
| 2248 | + position: absolute; | |
| 2249 | + box-sizing: border-box; | |
| 2250 | + margin: 50px auto; | |
| 2251 | + padding: 20px; | |
| 2252 | + width: 280px; | |
| 2253 | + z-index: 9999; | |
| 2254 | + left: 40%; | |
| 2255 | + top: 20%; | |
| 2256 | + background: rgba(255, 255, 255, 0.5); | |
| 2246 | 2257 | } |
| 2247 | 2258 | \ No newline at end of file | ... | ... |
src/main/resources/static/real_control_v2/css/microphone.css
0 → 100644
src/main/resources/static/real_control_v2/css/microphone.png
0 → 100644
2.02 KB
src/main/resources/static/real_control_v2/fragments/line_schedule/context_menu/temp_sch/add_normal.html
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | <div class="uk-form-row"> |
| 16 | 16 | <label class="uk-form-label">上下行</label> |
| 17 | 17 | <div class="uk-form-controls"> |
| 18 | - <select name="xlDir"> | |
| 18 | + <select name="xlDir" id="xlDir"> | |
| 19 | 19 | <option value="0">上行</option> |
| 20 | 20 | <option value="1">下行</option> |
| 21 | 21 | </select> |
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | <div class="uk-form-row"> |
| 29 | 29 | <label class="uk-form-label">起点站</label> |
| 30 | 30 | <div class="uk-form-controls"> |
| 31 | - <select name="qdzCode"> | |
| 31 | + <select name="qdzCode" id="qdzCode"> | |
| 32 | 32 | </select> |
| 33 | 33 | </div> |
| 34 | 34 | </div> |
| ... | ... | @@ -37,7 +37,7 @@ |
| 37 | 37 | <div class="uk-form-row"> |
| 38 | 38 | <label class="uk-form-label">终点站</label> |
| 39 | 39 | <div class="uk-form-controls"> |
| 40 | - <select name="zdzCode"> | |
| 40 | + <select name="zdzCode" id="zdzCode"> | |
| 41 | 41 | </select> |
| 42 | 42 | </div> |
| 43 | 43 | </div> |
| ... | ... | @@ -166,11 +166,16 @@ |
| 166 | 166 | //字典转换 |
| 167 | 167 | dictionaryUtils.transformDom($('.nt-dictionary', f)); |
| 168 | 168 | //validation |
| 169 | + | |
| 169 | 170 | f.formValidation({framework: 'uikit', locale: 'zh_CN'}); |
| 170 | 171 | //autocomp |
| 171 | 172 | f.trigger('init-autoCom'); |
| 172 | 173 | |
| 174 | + $("#xlDir").val(sch.xlDir); | |
| 173 | 175 | $f('bcType', f).trigger('change'); |
| 176 | + $("#qdzCode").val(sch.qdzCode); | |
| 177 | + $("#zdzCode").val(sch.zdzCode); | |
| 178 | + $f('zdzCode', f).trigger('change'); | |
| 174 | 179 | return f; |
| 175 | 180 | } |
| 176 | 181 | ... | ... |
src/main/resources/static/real_control_v2/js/data/json/north_toolbar.json
src/main/resources/static/real_control_v2/js/line_schedule/sch_table.js
| 1 | 1 | /** schedule table */ |
| 2 | 2 | |
| 3 | 3 | var gb_schedule_table = (function () { |
| 4 | - | |
| 4 | + var TablelineCode; | |
| 5 | 5 | var temps; |
| 6 | 6 | //线路分组的班次数据 |
| 7 | 7 | var line2Schedule = {}; |
| ... | ... | @@ -65,6 +65,7 @@ var gb_schedule_table = (function () { |
| 65 | 65 | var lineCode, dirData, htmlStr; |
| 66 | 66 | $('#main-tab-content .line_schedule').each(function () { |
| 67 | 67 | lineCode = $(this).data('id'); |
| 68 | + TablelineCode = lineCode; | |
| 68 | 69 | if (arrayIsNull(data[lineCode])) |
| 69 | 70 | return true; |
| 70 | 71 | dirData = gb_common.groupBy(data[lineCode], 'xlDir'); |
| ... | ... | @@ -937,6 +938,7 @@ var gb_schedule_table = (function () { |
| 937 | 938 | renderCarRemark: renderCarRemark, |
| 938 | 939 | putSCodeErrorInfo: putSCodeErrorInfo, |
| 939 | 940 | findSCodeErrorInfo: findSCodeErrorInfo, |
| 940 | - refreshRfid: refreshRfid | |
| 941 | + refreshRfid: refreshRfid, | |
| 942 | + TablelineCode : TablelineCode | |
| 941 | 943 | }; |
| 942 | 944 | })(); | ... | ... |
src/main/resources/static/real_control_v2/js/main.js
| 1 | 1 | /* main js */ |
| 2 | 2 | var gb_main_ep = new EventProxy(), |
| 3 | 3 | res_load_ep = EventProxy.create('load_data_basic', 'load_tab', 'load_home_layout', 'load_home_line_panel', function () { |
| 4 | + | |
| 5 | + | |
| 6 | + var recorder; | |
| 7 | + var fired = true; | |
| 8 | + document.onkeypress =function(e) { //对整个页面监听 | |
| 9 | + var keyNum = window.event ? e.keyCode : e.which; //获取被按下的键值 | |
| 10 | + //判断如果用户按下了回车键(keycody=13) | |
| 11 | + if (keyNum == 13) { | |
| 12 | + var id = document.getElementById("len"); | |
| 13 | + if(fired) | |
| 14 | + fired = false; | |
| 15 | + else | |
| 16 | + return | |
| 17 | + | |
| 18 | + document.getElementById("recidress").style.display = ""; | |
| 19 | + HZRecorder.get(function (rec) { | |
| 20 | + recorder = rec; | |
| 21 | + recorder.start(); | |
| 22 | + }); | |
| 23 | + | |
| 24 | + | |
| 25 | + } | |
| 26 | + } | |
| 27 | + | |
| 28 | + document.onkeyup =function(e) { //对整个页面监听 | |
| 29 | + var keyNum = window.event ? e.keyCode : e.which; //获取被按下的键值 | |
| 30 | + //判断如果用户按下了回车键(keycody=13) | |
| 31 | + if (keyNum == 13) { | |
| 32 | + fired = true; | |
| 33 | + debugger | |
| 34 | + let lineCode = gb_schedule_table.TablelineCode; | |
| 35 | + document.getElementById("recidress").style.display = 'none'; | |
| 36 | + recorder.upload("zndd/do/"+lineCode, function (state, e) { | |
| 37 | + switch (state) { | |
| 38 | + case 'uploading': | |
| 39 | + //var `percentComplete` = Math.round(e.loaded * 100 / e.total) + '%'; | |
| 40 | + break; | |
| 41 | + case 'ok': | |
| 42 | + // alert("识别成功"); | |
| 43 | + break; | |
| 44 | + case 'error': | |
| 45 | + alert("识别失败"); | |
| 46 | + break; | |
| 47 | + case 'cancel': | |
| 48 | + alert("识别被取消"); | |
| 49 | + break; | |
| 50 | + } | |
| 51 | + }); | |
| 52 | + } | |
| 53 | + }; | |
| 54 | + | |
| 4 | 55 | var eq = gb_main_ep; |
| 5 | 56 | // basic data end |
| 6 | 57 | eq.once('data-basic', g_emit('tab')); | ... | ... |
src/main/resources/static/real_control_v2/js/north/tabs.js
| ... | ... | @@ -56,6 +56,7 @@ var gb_tabs = (function() { |
| 56 | 56 | else if(area.attr('id')=='north_tabs_map_btn'){ |
| 57 | 57 | gb_map_overlay_mge.reload_gps(); |
| 58 | 58 | }*/ |
| 59 | + gb_schedule_table.TablelineCode = area[0].dataset.code; | |
| 59 | 60 | if(area.attr('id')=='north_tabs_map_btn'){ |
| 60 | 61 | gb_map_overlay_mge.reload_gps();//刷新地图 |
| 61 | 62 | } | ... | ... |
src/main/resources/static/real_control_v2/js/zndd/data_zndd.js
src/main/resources/static/real_control_v2/js/zndd/recorder/microphone.js
0 → 100644
| 1 | +var microphone = (function() { | |
| 2 | + function isIE() { | |
| 3 | + return !!window.ActiveXObject || 'ActiveXObject' in window ? true : false | |
| 4 | + } | |
| 5 | + var _volume = function(id, vol) { | |
| 6 | + var volID = document.getElementById(id); | |
| 7 | + volID.innerHTML = '<div style="width: 120px;height: 120px;border-radius: 60px;background: #fff;border:#daf3fc 1px solid;position: relative;">' + | |
| 8 | + '<span style="display: block;width: 30px;height: 65px;position: absolute;left: 9px;top:26px;">' + | |
| 9 | + '<span style="display: block;position:relative;width: 30px;height: 32px;margin-bottom: 1px;">' + | |
| 10 | + '<i style="display: block;position: absolute;left: 0;bottom: 0;width: 2px;background: #c5f0ff;height:' + 11 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.4) + '"></i>' + | |
| 11 | + '<i style="display: block;position: absolute;left: 4px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 14 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.2) + '"></i>' + | |
| 12 | + '<i style="display: block;position: absolute;left: 8px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 17 * vol / 100 + 'px;opacity:' + (vol / 100 + 0) + '"></i>' + | |
| 13 | + '<i style="display: block;position: absolute;left: 12px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 20 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.2) + '"></i>' + | |
| 14 | + '<i style="display: block;position: absolute;left: 16px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 23 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.4) + '"></i>' + | |
| 15 | + '<i style="display: block;position: absolute;left: 20px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 26 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.6) + '"></i>' + | |
| 16 | + '<i style="display: block;position: absolute;left: 24px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 29 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.8) + '"></i>' + | |
| 17 | + '<i style="display: block;position: absolute;left: 28px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 32 * vol / 100 + 'px;opacity:' + (vol / 100 + 1) + '"></i>' + | |
| 18 | + '</span>' + | |
| 19 | + '<span style="display: block;position:relative;width: 30px;height: 32px;">' + | |
| 20 | + '<i style="display: block;position: absolute;left: 0;top: 0;width: 2px;background: #c5f0ff;height:' + 11 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.4) + '"></i>' + | |
| 21 | + '<i style="display: block;position: absolute;left: 4px;top: 0;width: 2px;background: #c5f0ff;height:' + 14 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.2) + '"></i>' + | |
| 22 | + '<i style="display: block;position: absolute;left: 8px;top: 0;width: 2px;background: #c5f0ff;height:' + 17 * vol / 100 + 'px;opacity:' + (vol / 100 + 0) + '"></i>' + | |
| 23 | + '<i style="display: block;position: absolute;left: 12px;top: 0;width: 2px;background: #c5f0ff;height:' + 20 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.2) + '"></i>' + | |
| 24 | + '<i style="display: block;position: absolute;left: 16px;top: 0;width: 2px;background: #c5f0ff;height:' + 23 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.4) + '"></i>' + | |
| 25 | + '<i style="display: block;position: absolute;left: 20px;top: 0;width: 2px;background: #c5f0ff;height:' + 26 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.6) + '"></i>' + | |
| 26 | + '<i style="display: block;position: absolute;left: 24px;top: 0;width: 2px;background: #c5f0ff;height:' + 29 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.8) + '"></i>' + | |
| 27 | + '<i style="display: block;position: absolute;left: 28px;top: 0;width: 2px;background: #c5f0ff;height:' + 32 * vol / 100 + 'px;opacity:' + (vol / 100 + 1) + '"></i>' + | |
| 28 | + '</span>' + | |
| 29 | + '</span>' + | |
| 30 | + '<span style="display:block;margin:31px auto;width: 36px;height: 58px;" class="voluemImg"></span>' + | |
| 31 | + '<span style="display: block;width: 30px;height: 65px;position: absolute;right: 9px;top:26px;">' + | |
| 32 | + '<span style="display: block;position:relative;width: 30px;height: 32px;margin-bottom: 1px;">' + | |
| 33 | + '<i style="display: block;position: absolute;left: 0;bottom: 0;width: 2px;background: #c5f0ff;height:' + 32 * vol / 100 + 'px;opacity:' + (vol / 100 + 1) + '"></i>' + | |
| 34 | + '<i style="display: block;position: absolute;left: 4px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 29 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.8) + '"></i>' + | |
| 35 | + '<i style="display: block;position: absolute;left: 8px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 26 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.6) + '"></i>' + | |
| 36 | + '<i style="display: block;position: absolute;left: 12px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 23 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.4) + '"></i>' + | |
| 37 | + '<i style="display: block;position: absolute;left: 16px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 20 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.2) + '"></i>' + | |
| 38 | + '<i style="display: block;position: absolute;left: 20px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 17 * vol / 100 + 'px;opacity:' + (vol / 100 + 0) + '"></i>' + | |
| 39 | + '<i style="display: block;position: absolute;left: 24px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 14 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.2) + '"></i>' + | |
| 40 | + '<i style="display: block;position: absolute;left: 28px;bottom: 0;width: 2px;background: #c5f0ff;height:' + 11 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.4) + '"></i>' + | |
| 41 | + '</span>' + | |
| 42 | + '<span style="display: block;position:relative;width: 30px;height: 32px;">' + | |
| 43 | + '<i style="display: block;position: absolute;left: 0;top: 0;width: 2px;background: #c5f0ff;height:' + 32 * vol / 100 + 'px;opacity:' + (vol / 100 + 1) + '"></i>' + | |
| 44 | + '<i style="display: block;position: absolute;left: 4px;top: 0;width: 2px;background: #c5f0ff;height:' + 29 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.8) + '"></i>' + | |
| 45 | + '<i style="display: block;position: absolute;left: 8px;top: 0;width: 2px;background: #c5f0ff;height:' + 26 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.6) + '"></i>' + | |
| 46 | + '<i style="display: block;position: absolute;left: 12px;top: 0;width: 2px;background: #c5f0ff;height:' + 23 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.4) + '"></i>' + | |
| 47 | + '<i style="display: block;position: absolute;left: 16px;top: 0;width: 2px;background: #c5f0ff;height:' + 20 * vol / 100 + 'px;opacity:' + (vol / 100 + 0.2) + '"></i>' + | |
| 48 | + '<i style="display: block;position: absolute;left: 20px;top: 0;width: 2px;background: #c5f0ff;height:' + 17 * vol / 100 + 'px;opacity:' + (vol / 100 + 0) + '"></i>' + | |
| 49 | + '<i style="display: block;position: absolute;left: 24px;top: 0;width: 2px;background: #c5f0ff;height:' + 14 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.2) + '"></i>' + | |
| 50 | + '<i style="display: block;position: absolute;left: 28px;top: 0;width: 2px;background: #c5f0ff;height:' + 11 * vol / 100 + 'px;opacity:' + (vol / 100 - 0.4) + '"></i>' + | |
| 51 | + '</span>' + | |
| 52 | + '</span>' + | |
| 53 | + '</div>'; | |
| 54 | + } | |
| 55 | + return { | |
| 56 | + volume: _volume | |
| 57 | + }; | |
| 58 | +})(); | |
| 0 | 59 | \ No newline at end of file | ... | ... |
src/main/resources/static/real_control_v2/js/zndd/recorder/recorder.js
| ... | ... | @@ -187,76 +187,40 @@ |
| 187 | 187 | //notify_succ("您说的是:"+responseText[0]); |
| 188 | 188 | |
| 189 | 189 | console.log(responseText); // 这里会输出 "Hello, World!" |
| 190 | - let switchs = responseText[1]; | |
| 191 | - let storage = window.localStorage; | |
| 192 | - if (switchs == 0){ | |
| 193 | - storage.setItem("switchType", 1); //1开启 | |
| 194 | - succll(responseText[0],zzdopen); | |
| 195 | - } else if (switchs == 1){ | |
| 196 | - storage.setItem("switchType", 0); //0关闭 | |
| 197 | - succll(responseText[0],zzdclone); | |
| 198 | - | |
| 199 | - } else if (switchs == 2){ //临加班次 | |
| 200 | - let lineCode = gb_schedule_table.TablelineCode; | |
| 201 | - //打开临加班次 | |
| 202 | - var folder = '/real_control_v2/fragments/line_schedule/context_menu'; | |
| 203 | - var modal_opts = { | |
| 204 | - center: false, | |
| 205 | - bgclose: false | |
| 206 | - }; | |
| 207 | - | |
| 208 | - debugger | |
| 209 | - | |
| 210 | - /*$.post('/znddLogger/schlist/'+lineCode,function(sch) { | |
| 211 | - sch.dir = responseText[3] == null ? sch.dir : responseText[3] | |
| 212 | - sch.fcsj = responseText[4] == null ? sch.fcsj : responseText[4] | |
| 213 | - if (sch != null && sch != "") { | |
| 214 | - open_modal(folder + '/temp_sch/main.html', { | |
| 215 | - sch: sch | |
| 216 | - }, modal_opts); | |
| 217 | - }else { | |
| 218 | - errll(nosche); | |
| 219 | - } | |
| 220 | - });*/ | |
| 221 | - } else if (switchs == 3){ //撤销实发 | |
| 222 | - let lineCode = gb_schedule_table.TablelineCode; | |
| 223 | - var content = '<h3>确定要对<span>' +lineCode +'</span>'+撤销+ | |
| 224 | - '<span style="color:red;margin: 0 5px;">'+ responseText[4]+ '</span>的实发时间?</h3>' | |
| 225 | - alt_confirm(content, function () { | |
| 226 | - gb_common.$post('/realSchedule/revokeRealOutgo', { | |
| 227 | - id: that.data('id') | |
| 228 | - }, function (rs) { | |
| 229 | - gb_schedule_table.updateSchedule(rs.ts); | |
| 230 | - notify_succ('撤销实发操作成功!'); | |
| 231 | - //calc 应发未发 | |
| 232 | - gb_schedule_table.calc_yfwf_num(sch.xlBm); | |
| 233 | - | |
| 234 | - cb && cb(); | |
| 235 | - $(this).parent().remove(); | |
| 236 | - }); | |
| 237 | - }, '确认撤销实发'); | |
| 238 | - } else if (switchs == 4){ //撤销班次 | |
| 239 | - lineCode = responseText[2] == null ? lineCode : responseText[2] | |
| 240 | - var content = '<h3>确定要对<span>' +lineCode +'</span>'+取消+ | |
| 241 | - '<span style="color:red;margin: 0 5px;">'+ responseText[4]+ '</span>的班次?</h3>' | |
| 242 | - alt_confirm(content, function () { | |
| 243 | - gb_common.$post('/realSchedule/deleteRealSchedule', { | |
| 244 | - id: that.data('id') | |
| 245 | - }, function (rs) { | |
| 246 | - gb_schedule_table.updateSchedule(rs.ts); | |
| 247 | - notify_succ('撤销实发操作成功!'); | |
| 248 | - //calc 应发未发 | |
| 249 | - gb_schedule_table.calc_yfwf_num(sch.xlBm); | |
| 250 | - | |
| 251 | - cb && cb(); | |
| 252 | - $(this).parent().remove(); | |
| 253 | - }); | |
| 254 | - }, '确认撤销实发'); | |
| 255 | - }else{ | |
| 256 | - | |
| 257 | - errll(responseText[0],error); | |
| 190 | + | |
| 191 | + debugger | |
| 192 | + let lineCode = gb_schedule_table.TablelineCode; | |
| 193 | + //打开临加班次 | |
| 194 | + var folder = '/real_control_v2/fragments/line_schedule/context_menu'; | |
| 195 | + var modal_opts = { | |
| 196 | + center: false, | |
| 197 | + bgclose: false | |
| 198 | + }; | |
| 199 | + /*var sch ={ | |
| 200 | + xlBm : lineCode, | |
| 201 | + qdzCode : responseText[1], | |
| 202 | + zdzCode : responseText[2], | |
| 203 | + dir : responseText[3], | |
| 204 | + yuyin:111, | |
| 205 | + };*/ | |
| 206 | + let date = { | |
| 207 | + lineCode :lineCode, | |
| 208 | + dir:responseText[3], | |
| 258 | 209 | } |
| 259 | - | |
| 210 | + $.post('/logZndd/schlist',date,function(sch) { | |
| 211 | + debugger | |
| 212 | + sch.qdzCode = responseText[1]; | |
| 213 | + sch.zdzCode = responseText[2]; | |
| 214 | + sch.xlDir = responseText[3]; | |
| 215 | + sch.zdsjActual = moment(new Date()).format("HH:mm") | |
| 216 | + | |
| 217 | + open_modal(folder + '/temp_sch/main.html', { | |
| 218 | + sch: sch | |
| 219 | + }, modal_opts); | |
| 220 | + }); | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 260 | 224 | } |
| 261 | 225 | }; |
| 262 | 226 | ... | ... |
src/main/resources/static/real_control_v2/main.html
| ... | ... | @@ -47,6 +47,11 @@ |
| 47 | 47 | <!-- flatpickr --> |
| 48 | 48 | <link rel="stylesheet" href="/real_control_v2/assets/plugins/flatpickr/flatpickr.min.css" merge="plugins"> |
| 49 | 49 | <link rel="stylesheet" href="/real_control_v2/assets/plugins/flatpickr/themes/airbnb.css" merge="plugins"> |
| 50 | + | |
| 51 | + | |
| 52 | + <!-- main style --> | |
| 53 | + <link rel="stylesheet" href="/real_control_v2/css/microphone.css" /> | |
| 54 | + | |
| 50 | 55 | </head> |
| 51 | 56 | |
| 52 | 57 | <body> |
| ... | ... | @@ -322,6 +327,10 @@ |
| 322 | 327 | <script src="/real_control_v2/js/stationcf/stationcf.js" merge="custom_js"></script> |
| 323 | 328 | <!--智能调度--> |
| 324 | 329 | <script src="/real_control_v2/js/zndd/data_zndd.js" merge="custom_js"></script> |
| 330 | + | |
| 331 | +<!--语音图标--> | |
| 332 | +<script src="/real_control_v2/js/zndd//recorder/microphone.js"></script> | |
| 333 | + | |
| 325 | 334 | <!--recorder--> |
| 326 | 335 | <script src="/real_control_v2/js/zndd/recorder/recorder.js"></script> |
| 327 | 336 | <script src="/real_control_v2/js/zndd/recorder/recorders.js"></script> | ... | ... |