我有以下JSON文本。我如何解析它以获得pageName, pagePic, post_id等的值?
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
},
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": "1234567890",
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": "2",
"comments": [],
"timeOfPost": "1234567890"
}
]
}
由于还没有人提到它,这里是一个使用Nashorn (Java 8的JavaScript运行时部分,但在Java 11中已弃用)的解决方案的开始。
解决方案
private static final String EXTRACTOR_SCRIPT =
"var fun = function(raw) { " +
"var json = JSON.parse(raw); " +
"return [json.pageInfo.pageName, json.pageInfo.pagePic, json.posts[0].post_id];};";
public void run() throws ScriptException, NoSuchMethodException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(EXTRACTOR_SCRIPT);
Invocable invocable = (Invocable) engine;
JSObject result = (JSObject) invocable.invokeFunction("fun", JSON);
result.values().forEach(e -> System.out.println(e));
}
性能比较
我编写的JSON内容包含三个数组,分别为20、20和100个元素。我只想从第三个数组中获取100个元素。我使用下面的JavaScript函数来解析和获取我的条目。
var fun = function(raw) {JSON.parse(raw).entries};
使用Nashorn运行一百万次调用需要7.5~7.8秒
(JSObject) invocable.invokeFunction("fun", json);
org。Json需要20~21秒
new JSONObject(JSON).getJSONArray("entries");
杰克逊用时6.5~7秒
mapper.readValue(JSON, Entries.class).getEntries();
在这种情况下,Jackson的性能比Nashorn好,后者的性能比org.json好得多。
Nashorn API比org更难使用。json或Jackson的。根据您的需求,Jackson和Nashorn都是可行的解决方案。
除了其他答案,我推荐这个在线开源服务jsonschema2pojo.org,它可以从json或json模式快速生成Java类,用于GSON, Jackson 1。或者Jackson 2.x。例如,如果你有:
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
}
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": 1234567890,
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": 2,
"comments": [],
"timeOfPost": 1234567890
}
]
}
GSON的jsonschema2pojo.org生成:
@Generated("org.jsonschema2pojo")
public class Container {
@SerializedName("pageInfo")
@Expose
public PageInfo pageInfo;
@SerializedName("posts")
@Expose
public List<Post> posts = new ArrayList<Post>();
}
@Generated("org.jsonschema2pojo")
public class PageInfo {
@SerializedName("pageName")
@Expose
public String pageName;
@SerializedName("pagePic")
@Expose
public String pagePic;
}
@Generated("org.jsonschema2pojo")
public class Post {
@SerializedName("post_id")
@Expose
public String postId;
@SerializedName("actor_id")
@Expose
public long actorId;
@SerializedName("picOfPersonWhoPosted")
@Expose
public String picOfPersonWhoPosted;
@SerializedName("nameOfPersonWhoPosted")
@Expose
public String nameOfPersonWhoPosted;
@SerializedName("message")
@Expose
public String message;
@SerializedName("likesCount")
@Expose
public long likesCount;
@SerializedName("comments")
@Expose
public List<Object> comments = new ArrayList<Object>();
@SerializedName("timeOfPost")
@Expose
public long timeOfPost;
}
JSON是这样的:
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
}
}
Java类
class PageInfo {
private String pageName;
private String pagePic;
// Getters and setters
}
将此JSON转换为Java类的代码。
PageInfo pageInfo = JsonPath.parse(jsonString).read("$.pageInfo", PageInfo.class);
Maven
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
</dependency>
可以使用Apache @Model注释创建表示JSON文件结构的Java模型类,并使用它们访问JSON树中的各种元素。与其他解决方案不同,该解决方案完全没有反射,因此适用于不可能反射或开销很大的环境。
有一个示例Maven项目展示了这种用法。首先它定义了结构:
@Model(className="RepositoryInfo", properties = {
@Property(name = "id", type = int.class),
@Property(name = "name", type = String.class),
@Property(name = "owner", type = Owner.class),
@Property(name = "private", type = boolean.class),
})
final class RepositoryCntrl {
@Model(className = "Owner", properties = {
@Property(name = "login", type = String.class)
})
static final class OwnerCntrl {
}
}
然后它使用生成的RepositoryInfo和Owner类来解析所提供的输入流,并在此过程中获取某些信息:
List<RepositoryInfo> repositories = new ArrayList<>();
try (InputStream is = initializeStream(args)) {
Models.parse(CONTEXT, RepositoryInfo.class, is, repositories);
}
System.err.println("there is " + repositories.size() + " repositories");
repositories.stream().filter((repo) -> repo != null).forEach((repo) -> {
System.err.println("repository " + repo.getName() +
" is owned by " + repo.getOwner().getLogin()
);
})
就是这样!除此之外,这里还有一个生动的要点,展示了类似的例子以及异步网络通信。
你可以使用Jayway JsonPath。下面是一个GitHub链接,包括源代码、pom细节和良好的文档。
https://github.com/jayway/JsonPath
请按照以下步骤操作。
步骤1:使用Maven在类路径中添加jayway JSON路径依赖项,或者下载JAR文件并手动添加它。
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
</dependency>
步骤2:请将输入的JSON保存为本示例的文件。在我的情况下,我将JSON保存为sampleJson.txt。注意,pageInfo和posts之间没有逗号。
步骤3:使用bufferedReader从上面的文件中读取JSON内容,并将其保存为String。
BufferedReader br = new BufferedReader(new FileReader("D:\\sampleJson.txt"));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
br.close();
String jsonInput = sb.toString();
步骤4:使用jayway JSON解析器解析JSON字符串。
Object document = Configuration.defaultConfiguration().jsonProvider().parse(jsonInput);
第五步:像下面这样阅读细节。
String pageName = JsonPath.read(document, "$.pageInfo.pageName");
String pagePic = JsonPath.read(document, "$.pageInfo.pagePic");
String post_id = JsonPath.read(document, "$.posts[0].post_id");
System.out.println("$.pageInfo.pageName " + pageName);
System.out.println("$.pageInfo.pagePic " + pagePic);
System.out.println("$.posts[0].post_id " + post_id);
输出将是:
$.pageInfo.pageName = abc
$.pageInfo.pagePic = http://example.com/content.jpg
$.posts[0].post_id = 123456789012_123456789012