但發現 Java SE 預設的 API 並沒有 Json Parser ,需要 Java EE 才有預設 Json Parser
json.org 提供讓 Java 的 Json Parser ,但在下對其操作方式有點不明白,因此愚蠢地自己寫一個 Java 的 Json Parser
根據 json.org 定義,Json 的物件稱為 value 共有 7種 可視型態:
- object
- array
- string
- number
- true
- false
- null
建立 JsonValue 的抽象類別
public abstract class JsonValue<T> {
private final T value;
public JsonValue(T value) {
this.value = value;
}
public T getValue() {
return this.value;
}
}使用 Java 的 Generic 功能讓子類別根據需要改變成不同類別先處理 string, number, true, false, null
public class JsonString extends JsonValue<String> {
public JsonString(String value) {
super(value);
}
}public abstract class JsonNumber<T extends Number> extends JsonValue<Number> {
public JsonNumber(Number value) {
super(value);
}
}public class JsonInteger extends JsonNumber<Integer> {
public JsonInteger(int value) {
super(value);
}
}public class JsonFloat extends JsonNumber<Float> {
public JsonFloat(float value) {
super(value);
}
}借用 Number 的概念public abstract class JsonBoolean extends JsonValue<Boolean> {
public JsonBoolean(Boolean value) {
super(value);
}
}public class JsonTrue extends JsonBoolean {
public JsonTrue() {
super(true);
}
}public class JsonFalse extends JsonBoolean {
public JsonFalse() {
super(false);
}
}public class JsonNull extends JsonBoolean {
public JsonNull() {
super(null);
}
}借用 Boolean 製作 JsonNull 類別Json array 則是一個 value 的集合,而 array 自己也是集合之一
public class JsonArray extends JsonValue<JsonValue[]> {
private ArrayList<JsonValue> values = new ArrayList<>();
public JsonArray() {
this(new JsonValue[0]);
}
public JsonArray(JsonValue[] value) {
super(null);
this.values.addAll(Arrays.asList(value));
}
public void addValue(JsonValue value) {
this.values.add(value);
}
@Override
public JsonValue[] getValue() {
return this.values.toArray(new JsonValue[this.values.size()]);
}
public JsonValue getValue(int index) {
return this.values.get(index);
}
}最後是 Json object
object 由 key 及 value 的配對組成
key 必須是 string ,而 object 自己也是 value 之一
自訂 Json attribute
public class JsonAttribute {
private final String key;
private final JsonValue value;
public JsonAttribute(String key, JsonValue value) {
this.key = key;
this.value = value;
}
public String getKey() {
return this.key;
}
public JsonValue getValue() {
return this.value;
}
}public class JsonObject extends JsonValue<JsonAttribute[]> {
private ArrayList<JsonAttribute> values = new ArrayList<>();
public JsonObject() {
this(new JsonAttribute[0]);
}
public JsonObject(JsonAttribute[] value) {
super(null);
this.values.addAll(Arrays.asList(value));
}
public void addValue(JsonAttribute value) {
this.values.add(value);
}
@Override
public JsonAttribute[] getValue() {
return this.values.toArray(new JsonAttribute[this.values.size()]);
}
public JsonValue getValue(String key) {
for (JsonAttribute value : values) {
if (value.getKey().equals(key)) {
return value.getValue();
}
}
return null;
}
}由於 JsonArray 及 JsonObject 的結構問題,因此不能直接使用 JsonValue[] 及 JsonAttribute[]
必須額外設定為可擴充的陣列例如 ArrayList ,而傳回的功能亦需要覆寫
定義各種 Json value 後便需要解柝一組字串是否 Json
static Stack<String> extract(String json) throws Exception {
json = json.trim();
Stack<Character> bracketPairs = new Stack<>();
Stack<String> strings = new Stack<>();
StringBuilder tempString = new StringBuilder();
boolean openEscape = false;
boolean openString = false;
int length = json.length();
for (int i = 0; i < length; i++) {
char c = json.charAt(i);
tempString.append(c);
switch (c) {
case '{': {
if (openString) {
openEscape = false;
} else {
bracketPairs.push(c);
strings.push(tempString.toString().trim());
tempString.delete(0, tempString.length());
}
}
break;
case '}': {
if (openString) {
openEscape = false;
} else {
if (bracketPairs.peek() == '{') {
bracketPairs.pop();
String string = tempString.toString().trim();
int index = string.lastIndexOf('}');
String previous = string.substring(0, index).trim();
if (previous.length() > 0) {
strings.push(previous);
}
strings.push(string.substring(index).trim());
tempString.delete(0, tempString.length());
} else {
throw new Exception("Error Message");
}
}
}
break;
case '[': {
if (openString) {
openEscape = false;
} else {
bracketPairs.push(c);
strings.push(tempString.toString().trim());
tempString.delete(0, tempString.length());
}
}
break;
case ']': {
if (openString) {
openEscape = false;
} else {
if (bracketPairs.peek() == '[') {
bracketPairs.pop();
String string = tempString.toString().trim();
int index = string.lastIndexOf(']');
String previous = string.substring(0, index).trim();
if (previous.length() > 0) {
strings.push(previous);
}
strings.push(string.substring(index).trim());
tempString.delete(0, tempString.length());
} else {
throw new Exception("Error Message");
}
}
}
break;
case ':': {
if (openString) {
openEscape = false;
} else {
strings.push(tempString.toString().trim());
tempString.delete(0, tempString.length());
}
}
break;
case ',': {
if (openString) {
openEscape = false;
} else {
String string = tempString.toString().trim();
int index = string.lastIndexOf(',');
String previous = string.substring(0, index).trim();
if (previous.length() > 0) {
strings.push(previous);
}
strings.push(string.substring(index).trim());
tempString.delete(0, tempString.length());
}
}
break;
case '"': {
if (openString) {
if (openEscape) {
openEscape = false;
} else {
strings.push(tempString.toString().trim());
tempString.delete(0, tempString.length());
openString = false;
}
} else {
openString = true;
}
}
break;
case '\\': {
if (openString) {
openEscape = !openEscape;
}
}
break;
default: {
openEscape = false;
}
}
}
if (bracketPairs.empty()) {
return strings;
} else {
throw new Exception("Error Message");
}
}extract 只將「{」、「}」、「[」、「]」、「:」、「,」、「"」、 string 、其他資料分割及「\」跳脫字元處理,但不檢查合理性然後是判斷分割的資料屬於哪一種類型,還是不屬於任何類型的錯誤資料
null, true, false 最簡單
public static JsonNull parseJsonNull(String json) throws Exception {
json = json.trim();
if (json.equals("null")) {
return new JsonNull();
} else {
throw new Exception("Error Message");
}
}public static JsonTrue parseJsonTrue(String json) throws Exception {
json = json.trim();
if (json.equals("true")) {
return new JsonTrue();
} else {
throw new Exception("Error Message");
}
}public static JsonFalse parseJsonFalse(String json) throws Exception {
json = json.trim();
if (json.equals("false")) {
return new JsonFalse();
} else {
throw new Exception("Error Message");
}
}number 其實都比較繁複,整數、負數、浮點數、指數,但由於 Java 提供 number parser 的功能,借用 number parser 便可以輕鬆處理public static JsonNumber parseJsonInteger(String json) throws Exception {
json = json.trim();
try {
Double value = Double.parseDouble(json);
if (value % 1.0 == 0.0) {
return new JsonInteger(value.intValue());
} else {
throw new Exception("Error Message");
}
} catch (Exception ex) {
throw new Exception("Error Message");
}
}public static JsonFloat parseJsonFloat(String json) throws Exception {
json = json.trim();
try {
Double value = Double.parseDouble(json);
if (value % 1.0 != 0.0) {
return new JsonFloat(value.floatValue());
} else {
throw new Exception("Error Message");
}
} catch (Exception ex) {
throw new Exception("Error Message");
}
}若果閣下對數值資料不用區分 integer 或 float ,直接傳回 double 作 JsonNumber 亦可以string 與剛才的 extract 功能差不多,同樣需要分個字元檢查資料的正確
static final char CHAR_NULL = '\0';
static final char CHAR_BELL = '\7';
static final char CHAR_BACKSPACE = '\b';
static final char CHAR_LINE_FEED = '\n';
static final char CHAR_TAB = '\t';
static final char CHAR_VERTICAL_TAB = '\11';
static final char CHAR_FORM_FEED = '\f';
static final char CHAR_CARRIAGE_RETURN = '\r';
static final char CHAR_ESCAPE = '\27';
public static JsonString parseJsonString(String json) throws Exception {
json = json.trim();
if (json.length() < 2 || json.charAt(0) != '"' || json.charAt(json.length() - 1) != '"') {
throw new Exception("Error Message");
}
json = json.substring(1, json.length() - 1);
if (json.contains(Character.toString(CHAR_NULL))
|| json.contains(Character.toString(CHAR_BELL))
|| json.contains(Character.toString(CHAR_BACKSPACE))
|| json.contains(Character.toString(CHAR_LINE_FEED))
|| json.contains(Character.toString(CHAR_VERTICAL_TAB))
|| json.contains(Character.toString(CHAR_FORM_FEED))
|| json.contains(Character.toString(CHAR_CARRIAGE_RETURN))
|| json.contains(Character.toString(CHAR_ESCAPE))) {
throw new Exception("Error Message");
}
StringBuilder tempString = new StringBuilder();
boolean openEscape = false;
int length = json.length();
for (int i = 0; i < length; i++) {
char c = json.charAt(i);
switch (c) {
case 'b': {
if (openEscape) {
int tempLength = tempString.length();
if (tempLength > 0) {
tempString.delete(tempLength - 1, tempLength);
} else {
throw new Exception("Error Message");
}
} else {
tempString.append(c);
}
openEscape = false;
}
break;
case 'f': {
if (openEscape) {
tempString.append('\f');
} else {
tempString.append(c);
}
openEscape = false;
}
break;
case 'n': {
if (openEscape) {
tempString.append('\n');
} else {
tempString.append(c);
}
openEscape = false;
}
break;
case 'r': {
if (openEscape) {
tempString.append('\r');
} else {
tempString.append(c);
}
openEscape = false;
}
break;
case 't': {
if (openEscape) {
tempString.append('\t');
} else {
tempString.append(c);
}
openEscape = false;
}
break;
case 'u': {
if (openEscape) {
try {
String hexString = json.substring(i + 1, i + 5);
tempString.append((char) Integer.parseInt(hexString, 16));
i += 4;
} catch (Exception ex) {
throw new Exception("Error Message");
}
} else {
tempString.append(c);
}
openEscape = false;
}
break;
case '"': {
if (openEscape) {
tempString.append(c);
openEscape = false;
} else {
throw new Exception("Error Message");
}
}
break;
case '\\': {
if (openEscape) {
tempString.append(c);
}
openEscape = !openEscape;
}
break;
default: {
tempString.append(c);
openEscape = false;
}
}
}
json = tempString.toString();
return new JsonString(json);
}由於 string, number, true, false, null 為獨立型態,以一個 method 整合處理
static JsonValue parseJsonOther(String string) {
JsonValue jsonValue = null;
if (jsonValue == null) {
try {
jsonValue = parseJsonString(string);
} catch (Exception ex) {
}
}
if (jsonValue == null) {
try {
jsonValue = parseJsonFloat(string);
} catch (Exception ex) {
}
}
if (jsonValue == null) {
try {
jsonValue = parseJsonInteger(string);
} catch (Exception ex) {
}
}
if (jsonValue == null) {
try {
jsonValue = parseJsonFalse(string);
} catch (Exception ex) {
}
}
if (jsonValue == null) {
try {
jsonValue = parseJsonTrue(string);
} catch (Exception ex) {
}
}
if (jsonValue == null) {
try {
jsonValue = parseJsonNull(string);
} catch (Exception ex) {
}
}
return jsonValue;
}array 為一連串 Json Value 及 , 所組成
- 開啟 array 後,必須為 Json Value 或 ]
- 加入 Json Value 後,必須為 , 或 ]
- , 後,必須為 Json Value
static final int JSON_STATE_OPEN = 0;
static final int JSON_STATE_VALUE = JSON_STATE_OPEN + 1;
static final int JSON_STATE_COMMA = JSON_STATE_VALUE + 1;
static JsonArray parseJsonArray(Stack<String> strings, JsonArray jsonArray) throws Exception {
if (strings.size() > 0) {
int state = JSON_STATE_OPEN;
while (strings.size() > 0) {
String string = strings.remove(0);
if (string.equals("[")) {
if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) {
jsonArray.addValue(parseJsonArray(strings, new JsonArray()));
state = JSON_STATE_VALUE;
} else {
throw new Exception("Error Message");
}
} else if (string.equals("]")) {
if (state == JSON_STATE_OPEN || state == JSON_STATE_VALUE) {
break;
} else {
throw new Exception("Error Message");
}
} else if (string.equals("{")) {
if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) {
jsonArray.addValue(parseJsonObject(strings, new JsonObject()));
state = JSON_STATE_VALUE;
} else {
throw new Exception("Error Message");
}
} else if (string.equals(",")) {
if (state == JSON_STATE_VALUE) {
state = JSON_STATE_COMMA;
} else {
throw new Exception("Error Message");
}
} else {
if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) {
JsonValue jsonValue = parseJsonOther(string);
if (jsonValue == null) {
throw new Exception("Error Message");
} else {
jsonArray.addValue(jsonValue);
state = JSON_STATE_VALUE;
}
} else {
throw new Exception("Error Message");
}
}
}
return jsonArray;
} else {
return null;
}
}object 為一連串 key 、 : 、 Json Value 及 , 所組成
- 開啟 object 後,必須為 key 或 }
- key 後,必須為 :
- : 後,必須為 Json Value
- 加入 Json Value 後,必須為 , 或 }
- , 後,必須為 key
static final int JSON_STATE_OPEN = 0;
static final int JSON_STATE_KEY = JSON_STATE_OPEN + 1;
static final int JSON_STATE_COLON = JSON_STATE_KEY + 1;
static final int JSON_STATE_VALUE = JSON_STATE_COLON + 1;
static final int JSON_STATE_COMMA = JSON_STATE_VALUE + 1;
static JsonObject parseJsonObject(Stack<String> strings, JsonObject jsonObject) throws Exception {
if (strings.size() > 0) {
String key = null;
int state = JSON_STATE_OPEN;
while (strings.size() > 0) {
String string = strings.remove(0);
if (string.equals("{")) {
if (state == JSON_STATE_COLON) {
jsonObject.addValue(new JsonAttribute(key, parseJsonObject(strings, new JsonObject())));
state = JSON_STATE_VALUE;
} else {
throw new Exception("Error Message");
}
} else if (string.equals("}")) {
if (state == JSON_STATE_OPEN || state == JSON_STATE_VALUE) {
break;
} else {
throw new Exception("Error Message");
}
} else if (string.equals("[")) {
if (state == JSON_STATE_COLON) {
jsonObject.addValue(new JsonAttribute(key, parseJsonArray(strings, new JsonArray())));
state = JSON_STATE_VALUE;
} else {
throw new Exception("Error Message");
}
} else if (string.equals(":")) {
if (state == JSON_STATE_KEY) {
state = JSON_STATE_COLON;
} else {
throw new Exception("Error Message");
}
} else if (string.equals(",")) {
if (state == JSON_STATE_VALUE) {
state = JSON_STATE_COMMA;
} else {
throw new Exception("Error Message");
}
} else {
if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) {
try {
key = parseJsonString(string).getValue();
state = JSON_STATE_KEY;
} catch (Exception ex) {
throw new Exception("Error Message");
}
} else if (state == JSON_STATE_COLON) {
JsonValue jsonValue = parseJsonOther(string);
if (jsonValue == null) {
throw new Exception("Error Message");
} else {
jsonObject.addValue(new JsonAttribute(key, jsonValue));
state = JSON_STATE_VALUE;
}
} else {
throw new Exception("Error Message");
}
}
}
return jsonObject;
} else {
return null;
}
}最後整合所有功能
public static JsonValue parse(String json) throws Exception {
Stack<String> strings = extract(json);
if (strings.empty()) {
throw new Exception("Error Message");
} else {
String string = strings.remove(0);
if (string.equals("{")) {
return parseJsonObject(strings, new JsonObject());
} else if (string.equals("[")) {
return parseJsonArray(strings, new JsonArray());
} else {
throw new Exception("Error Message");
}
}
}由於 Json 必須以 { 或 [ 作初始,若字串清單的第一個字串不是 { 或 [ 或為錯誤另外由於使用了 Stack, ArrayList, Arrays 等類別,因此需要載入 java.util.*
在下以 Json @ Wiki 及 Google Map API Json 格式 檢查正常
以 Json @ Wiki 為例
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"height_cm": 167.6,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [],
"spouse": null
}JsonObject jsonObject = (JsonObject) parse(s);
System.out.println(((JsonString) jsonObject.getValue("firstName")).getValue());
System.out.println(((JsonBoolean) jsonObject.getValue("isAlive")).getValue());
System.out.println(((JsonNumber) jsonObject.getValue("age")).getValue());
System.out.println(((JsonNumber) jsonObject.getValue("height_cm")).getValue());
System.out.println(((JsonString) ((JsonObject) jsonObject.getValue("address")).getValue("streetAddress")).getValue());
System.out.println(((JsonString) ((JsonObject) ((JsonArray) jsonObject.getValue("phoneNumbers")).getValue(0)).getValue("type")).getValue());
System.out.println(((JsonBoolean) jsonObject.getValue("spouse")).getValue());輸出成John true 25 167.6 21 2nd Street home null避免資料發生 ClassCaseException 可以先用 instanceof 來檢查傳回資料能否轉型
同一個 Json object 的 Json attribute 的 key 重覆,會以新的 Json attribute 取代
由於在下使用 ArrayList 作為陣列又忽略了檢查重覆,會發生重覆 Json attribute
其實應該使用 HashMap 會比較適合,讓 Map 自動處理重覆的 key ,而使用 ArrayList 則需要由使用者自行處理
沒有留言 :
張貼留言