web-dev-qa-db-ja.com

引用符のないjson文字列をマップに変換します

Json形式の文字列があります。引用符で囲まれているのはキーまたは値だけではありません。たとえば、私はこれを持っています:

String json = "{name: Bob, state: Colorado, Friends: [{ name: Dan, age: 23 }, {name: Zane, age: 24 }]}"

これを次のようなマップにしたい:

Map<String, Object> friend1Map = new HashMap<>();
friend1Map.put("name", "Dan");
friend1Map.put("age", 23);

Map<String, Object> friend2Map = new Hashmap<>();
friend2Map.put("name", "Zane");
friend2Map.put("age", 24);

Map<String, Object> newMap = new HashMap<>();
newMap.put("name", "Bob");
newMap.put("state", "Colorado");
newMap.put("Friends", Arrays.asList(friend1Map, friend2Map));

私は次の2つの方法を試しました:

ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, new TypeReference<Map<String, Object>>() {});

これはエラーをスローします:

Unexpected character ('n'): was expecting double-quote to start field name

次に、マッパーの構成を変更してみました。

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.readValue(json, new TypeReference<Map<String, Object>>() {});

しかし、これは言ってエラーを投げました:

com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Bob': was expecting ('true', 'false' or 'null')
at [Source: {name: Bob, state: Colorado, Friends: [{ name: Dan, age: 23 }, {name: Zane, age: 24 }]}; line: 1, column: 11]

引用符がjson文字列に含まれていないときにこのマップを取得する方法はありますか?

13
user2869231

あなたの質問に答えるために:あなたのJSONを取得するsafe方法はありません-ところでJSONは無効であるため、Map<String, Object>に変換されます。

少し詳しく説明しましょう(なぜ安全に解析できないのですか?):次のような「JSON」を想像してください。

{
    this is my key: and here's my value and it even has a colon:
}

有効なJSONは次のようになります

{
    "this is my key": "and here's my value and it even has a colon:"
}

引用符を使用すると、パーサーはキーと値を安全に決定できます。それらがなければ、パーサーは失われます。

2
Brian

ObjectMapperは、Json入力が有効でない場合、それを解析できないため、答えは「いいえ」です。

ここであなたのJsonをテストしてください: http://jsonlint.com/

Json入力を修正した後、次のことができます。

    ObjectMapper ob = new ObjectMapper();
    ob.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    String json = "{name: \"Bob\", state: \"Colorado\", Friends: [{ name: \"Dan\", age: 23 }, {name: \"Zane\", age: 24 }]}";

    Map<String, ObjectNode> theMap = ob.readValue(json, Map.class);
    System.out.println(theMap.get("name"));

印刷されます:

ボブ

次のコードを使用してjson文字列を前処理してから解析できます。

String str = ("{requestid:\"55275645.f213506045\",timestamp:\"213506045\",bidnumber:\"55275645\",checkcode:\"1f6ad033de64d1c6357af34d4a38e9e3\",version:\"1.0\",request:{token:ee4e90c2-7a8b-4c73-bd48-1bda7e6734d5,referenceId:0.5878463922999799}}");
    str = (str.replaceAll(":\"?([^{|^]*?)\"?(?=[,|}|\\]])",":\"$1\"").replaceAll("\"?(\\w+)\"?(?=:)","\"$1\""));
    JSONObject obj = JSON.parseObject(str);
    System.out.println(obj.getJSONObject("request").getString("token"));
1
张凡杭

SINCE Java 14

注:Java 14(2020年3月のリリース)から)、エスケープされていない二重引用符をそのまま使用できます。

var json = """
        {"name": "Bob", "state": "Colorado", "Friends": [{ "name": "Dan", "age": 23 }, {"name": "Zane", "age": 24 }]} """;

詳細


GSON v2.8.6以降

Jackson fastxmlを使用したObjectMapperは、引用符なしの値をサポートしていませんが、GSONは以下をサポートしています。

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonParser;

  JsonNode json = json("{"
      + "  name: Bob,      "
      + "  state: Colorado,"
      + "  Friends: [      "
      + "    {"
      + "      name: Dan,  "
      + "      age: 23     "
      + "    },"
      + "    {"
      + "      name: Zane, "
      + "      age: 24     "
      + "     }"
      + "  ],"
      + "  extra: \"text with spaces or colon(:) must be quoted\""
      + "}");

  Map m = new ObjectMapper().convertValue(json, Map.class);

JsonNode json(String content) throws IOException {

  String canonicalFormat = JsonParser.parseString(content).toString();
  return json.readTree(canonicalFormat);
}

EARLIER GSON

V2.8.6より前のGSONには、静的なparseStringメソッドがありませんでした。したがって、(上位バージョンでは非推奨)インスタンスメソッドを使用する必要があります。

JsonNode json(String content) throws IOException {

  String canonicalFormat = new JsonParser().parse(content).toString();
  return json.readTree(canonicalFormat);
}
0
epox

Apache CommonsとGuavaベースライブラリを使用して、そのようなjsonをMapに変換できます。例:入力-{name = jack、id = 4}出力-Map(name = jack、id = 4)

import com.google.common.base.Splitter;
import org.Apache.commons.lang.StringUtils;

String input = StringUtils.substringBetween(value, "{", "}");
Map<String, String> map = 
Splitter.on(",").withKeyValueSeparator("=").split(input);
0
Dhruv