17370845950

在Java/Android中从JSONArray根据键获取特定值并进行筛选

本文详细介绍了在java和android开发中如何高效地解析json数组(jsonarray),从中提取特定键对应的值,并在此基础上实现数据筛选。内容涵盖json对象的遍历、值获取、异常处理以及结合实际场景(如根据邮箱地址筛选经纬度信息)的代码实现,旨在提供一个结构清晰、易于理解的教程。

1. 理解JSON数据结构

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。在Java和Android开发中,我们经常需要处理来自服务器的JSON数据。

JSON数据主要有两种基本结构:

  • JSON对象 (JSONObject):一个无序的“键/值”对集合。键是一个字符串,值可以是字符串、数字、布尔值、另一个JSON对象、JSON数组或null。在Java中通常对应 org.json.JSONObject 类。
  • JSON数组 (JSONArray):一个有序的值集合。每个值可以是任何JSON数据类型(字符串、数字、布尔值、JSON对象、JSON数组等)。在Java中通常对应 org.json.JSONArray 类。

本教程将重点讲解如何处理包含多个JSON对象的 JSONArray。

2. 解析JSONArray并提取数据

假设我们有一个包含多个用户位置信息的 JSONArray,每个对象包含 num、email、lati(纬度)、longt(经度)和 time 等字段。我们的目标是解析这个数组,并提取 lati 和 longt 值。

2.1 将JSON字符串转换为JSONArray对象

首先,你需要将接收到的JSON字符串转换为 JSONArray 对象。

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.List;

public class JsonParserExample {

    // 假设这是你从API获取到的JSON字符串
    private static final String JSON_DATA = "[" +
            "    {" +
            "        \"num\": \"34304\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888888\"," +
            "        \"longt\": \"88888888\"," +
            "        \"time\": \"2025-12-08 21:15:39\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34303\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34302\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34301\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34300\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }" +
            "]";

    public static void main(String[] args) {
        try {
            JSONArray jsonArray = new JSONArray(JSON_DATA);
            System.out.println("成功将JSON字符串转换为JSONArray,包含 " + jsonArray.length() + " 个元素。");
        } catch (JSONException e) {
            e.printStackTrace();
            System.err.println("JSON解析错误: " + e.getMessage());
        }
    }
}

2.2 遍历JSONArray并获取JSONObject

JSONArray 实际上是一个 JSONObject 的列表。我们需要遍历这个数组,对每个 JSONObject 进行处理。

// 假设你已经有了JSONArray jsonArray
for (int i = 0; i < jsonArray.length(); i++) {
    try {
        JSONObject jsonObject = jsonArray.getJSONObject(i); // 获取当前索引的JSONObject
        // 或者更安全的做法:
        // JSONObject jsonObject = jsonArray.optJSONObject(i); 
        // optJSONObject在索引越界或元素不是JSONObject时返回null,避免抛出JSONException

        // 现在可以从jsonObject中提取值
        String num = jsonObject.getString("num");
        String email = jsonObject.getString("email");
        String lati = jsonObject.getString("lati");
        String longt = jsonObject.getString("longt");
        String time = jsonObject.getString("time");

        System.out.println("--- 元素 " + i + " ---");
        System.out.println("Num: " + num);
        System.out.println("Email (raw): " + email);
        System.out.println("Lati: " + lati);
        System.out.println("Longt: " + longt);
        System.out.println("Time: " + time);

    } catch (JSONException e) {
        e.printStackTrace();
        System.err.println("处理JSONArray中的元素时发生错误: " + e.getMessage());
    }
}

2.3 从JSONObject中提取特定值

JSONObject 提供了多种方法来获取不同类型的值:

  • getString(String key): 获取字符串值。
  • getInt(String key): 获取整数值。
  • getDouble(String key): 获取双精度浮点数值。
  • getBoolean(String key): 获取布尔值。
  • getJSONObject(String key): 获取嵌套的JSONObject。
  • getJSONArray(String key): 获取嵌套的JSONArray。

与 get 方法对应的,还有 opt 方法(如 optString、optInt 等)。opt 方法在键不存在时不会抛出 JSONException,而是返回一个默认值(例如 optString 返回空字符串,optInt 返回0,optJSONObject 返回null),这在处理可选字段时非常有用。

在我们的例子中,lati 和 longt 都是字符串类型,但我们通常需要将它们转换为 double 类型以表示地理坐标。

// ... 在上面的for循环内部 ...
String latiStr = jsonObject.getString("lati");
String longtStr = jsonObject.getString("longt");

try {
    double latitude = Double.parseDouble(latiStr);
    double longitude = Double.parseDouble(longtStr);
    System.out.println("Parsed Lati: " + latitude + ", Parsed Longt: " + longitude);
    // 可以在这里将latitude和longitude存储到自定义对象或列表中
} catch (NumberFormatException e) {
    System.err.println("纬度或经度值格式错误: " + latiStr + ", " + longtStr);
}

3. 应用筛选逻辑:根据Email筛选数据

原始问题要求根据特定的邮箱地址筛选数据。在我们的JSON数据中,email 字段是一个HTML 标签,其中包含了实际的邮箱地址。我们需要先从这个HTML标签中提取出纯文本的邮箱地址,然后再进行筛选。

3.1 提取纯文本Email地址

由于 email 字段是 [email protected] 这样的HTML结构,直接获取 getString("email") 会得到整个HTML字符串。我们需要从这个字符串中提取 [email protected]。一种简单的方法是使用正则表达式或字符串替换来移除HTML标签。

// 辅助方法:从HTML字符串中提取纯文本邮箱
private static String extractEmailFromHtml(String htmlEmail) {
    // 移除所有HTML标签
    String plainText = htmlEmail.replaceAll("<[^>]*>", "");
    // 替换HTML实体   为普通空格
    plainText = plainText.replace(" ", " ");
    return plainText.trim();
}

// ... 在for循环内部,获取email字符串后 ...
String rawEmail = jsonObject.getString("email");
String cleanEmail = extractEmailFromHtml(rawEmail);
System.out.println("Cleaned Email: " + cleanEmail);

// 假设我们要筛选的邮箱是 "[email protected]"
String targetEmail = "[email protected]";

if (cleanEmail.equals(targetEmail)) {
    // 匹配成功,提取经纬度
    String latiStr = jsonObject.getString("lati");
    String longtStr = jsonObject.getString("longt");
    try {
        double latitude = Double.parseDouble(latiStr);
        double longitude = Double.parseDouble(longtStr);
        System.out.println("--- 找到匹配邮箱的数据 ---");
        System.out.println("Email: " + cleanEmail);
        System.out.println("Lati: " + latitude);
        System.out.println("Longt: " + longitude);
        // 将匹配的经纬度添加到结果列表中
    } catch (NumberFormatException e) {
        System.err.println("筛选后纬度或经度值格式错误: " + latiStr + ", " + longtStr);
    }
}

4. 完整示例代码

结合上述所有步骤,下面是一个完整的Java代码示例,演示如何解析JSON数组,提取经纬度,并根据邮箱地址进行筛选。

为了更好地组织数据,我们定义一个简单的 LatLng 类来存储经纬度。

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

// 模拟Android中的LatLng类
class LatLng {
    public double latitude;
    public double longitude;

    public LatLng(double latitude, double longitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

    @Override
    public String toString() {
        return "LatLng{" +
               "latitude=" + latitude +
               ", longitude=" + longitude +
               '}';
    }
}

public class JsonDataProcessor {

    private static final String JSON_DATA = "[" +
            "    {" +
            "        \"num\": \"34304\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888888\"," +
            "        \"longt\": \"88888888\"," +
            "        \"time\": \"2025-12-08 21:15:39\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34303\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34302\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34301\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }," +
            "    {" +
            "        \"num\": \"34300\"," +
            "        \"email\": \"[email protected]\"," +
            "        \"lati\": \"8888\"," +
            "        \"longt\": \"88888\"," +
            "        \"time\": \"8888888\"" +
            "    }" +
            "]";

    /**
     * 从HTML字符串中提取纯文本邮箱地址。
     * 例如,从 "[email protected]" 提取 "[email protected]"
     *
     * @param htmlEmail 包含邮箱的HTML字符串
     * @return 纯文本邮箱地址,如果无法提取则返回空字符串。
     */
    private static String extractEmailFromHtml(String htmlEmail) {
        // 使用正则表达式匹配标签内部的文本内容
        // Pattern pattern = Pattern.compile("(?<=>)(.*?)(?=<)"); // 匹配标签内部所有内容
        // 更精确地匹配 [email @] 格式
        Pattern pattern = Pattern.compile("\\[email @\\][^\\]]*"); // 匹配 [email @] 后面的内容直到 ]
        Matcher matcher = pattern.matcher(htmlEmail);
        if (matcher.find()) {
            String extracted = matcher.group(0);
            // 替换HTML实体