在这里插入图片描述

项目概述

JSON 解析是现代应用开发中的基础功能。无论是在 API 通信、数据存储、配置管理还是数据交换中,都需要进行 JSON 的解析和生成。然而,不同的编程语言和平台对 JSON 处理的实现方式各不相同,这导致开发者需要在不同平台上重复编写类似的逻辑。

本文介绍一个基于 Kotlin Multiplatform (KMP) 和 OpenHarmony 平台的 JSON 解析库示例。这个库提供了一套完整的 JSON 处理能力,包括 JSON 解析、对象序列化、数据验证等功能。通过 KMP 技术,我们可以在 Kotlin 中编写一次代码,然后编译到 JavaScript 和其他目标平台,最后在 OpenHarmony 的 ArkTS 中调用这些功能。

技术架构

多平台支持

  • Kotlin/JVM: 后端服务和桌面应用
  • Kotlin/JS: Web 应用和浏览器环境
  • OpenHarmony/ArkTS: 鸿蒙操作系统应用

核心功能模块

  1. JSON 解析: 解析 JSON 字符串为对象
  2. 对象序列化: 将对象转换为 JSON 字符串
  3. 数据验证: 验证 JSON 数据的有效性
  4. 嵌套处理: 处理复杂的嵌套 JSON 结构
  5. 数组处理: 处理 JSON 数组
  6. 类型转换: 在不同类型之间进行转换
  7. 错误处理: 处理 JSON 解析错误
  8. 性能优化: 优化 JSON 处理性能

Kotlin 实现

核心 JSON 解析类

// 文件: src/commonMain/kotlin/JsonParser.kt

/**
 * JSON 解析工具类
 * 提供 JSON 解析、序列化、验证等功能
 */
class JsonParser {
    
    sealed class JsonValue {
        data class JsonString(val value: String) : JsonValue()
        data class JsonNumber(val value: Double) : JsonValue()
        data class JsonBoolean(val value: Boolean) : JsonValue()
        data class JsonObject(val value: Map<String, JsonValue>) : JsonValue()
        data class JsonArray(val value: List<JsonValue>) : JsonValue()
        object JsonNull : JsonValue()
    }
    
    /**
     * 解析 JSON 字符串
     * @param json JSON 字符串
     * @return 解析结果
     */
    fun parse(json: String): Result<JsonValue> {
        return try {
            val trimmed = json.trim()
            val (value, _) = parseValue(trimmed, 0)
            Result.success(value)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    /**
     * 解析 JSON 值
     */
    private fun parseValue(json: String, index: Int): Pair<JsonValue, Int> {
        var i = skipWhitespace(json, index)
        
        return when {
            json[i] == '{' -> parseObject(json, i)
            json[i] == '[' -> parseArray(json, i)
            json[i] == '"' -> parseString(json, i)
            json[i] == 't' || json[i] == 'f' -> parseBoolean(json, i)
            json[i] == 'n' -> parseNull(json, i)
            else -> parseNumber(json, i)
        }
    }
    
    /**
     * 解析 JSON 对象
     */
    private fun parseObject(json: String, index: Int): Pair<JsonValue, Int> {
        var i = index + 1
        val map = mutableMapOf<String, JsonValue>()
        
        i = skipWhitespace(json, i)
        if (json[i] == '}') return Pair(JsonValue.JsonObject(map), i + 1)
        
        while (true) {
            i = skipWhitespace(json, i)
            val (keyValue, keyEnd) = parseString(json, i)
            val key = (keyValue as JsonValue.JsonString).value
            
            i = skipWhitespace(json, keyEnd)
            if (json[i] != ':') throw IllegalArgumentException("Expected ':'")
            i = skipWhitespace(json, i + 1)
            
            val (value, valueEnd) = parseValue(json, i)
            map[key] = value
            i = skipWhitespace(json, valueEnd)
            
            when {
                json[i] == '}' -> return Pair(JsonValue.JsonObject(map), i + 1)
                json[i] == ',' -> i = skipWhitespace(json, i + 1)
                else -> throw IllegalArgumentException("Expected ',' or '}'")
            }
        }
    }
    
    /**
     * 解析 JSON 数组
     */
    private fun parseArray(json: String, index: Int): Pair<JsonValue, Int> {
        var i = index + 1
        val list = mutableListOf<JsonValue>()
        
        i = skipWhitespace(json, i)
        if (json[i] == ']') return Pair(JsonValue.JsonArray(list), i + 1)
        
        while (true) {
            val (value, valueEnd) = parseValue(json, i)
            list.add(value)
            i = skipWhitespace(json, valueEnd)
            
            when {
                json[i] == ']' -> return Pair(JsonValue.JsonArray(list), i + 1)
                json[i] == ',' -> i = skipWhitespace(json, i + 1)
                else -> throw IllegalArgumentException("Expected ',' or ']'")
            }
        }
    }
    
    /**
     * 解析 JSON 字符串
     */
    private fun parseString(json: String, index: Int): Pair<JsonValue, Int> {
        var i = index + 1
        val sb = StringBuilder()
        
        while (json[i] != '"') {
            if (json[i] == '\\') {
                i++
                when (json[i]) {
                    '"' -> sb.append('"')
                    '\\' -> sb.append('\\')
                    '/' -> sb.append('/')
                    'b' -> sb.append('\b')
                    'f' -> sb.append('\u000C')
                    'n' -> sb.append('\n')
                    'r' -> sb.append('\r')
                    't' -> sb.append('\t')
                    'u' -> {
                        val hex = json.substring(i + 1, i + 5)
                        sb.append(hex.toInt(16).toChar())
                        i += 4
                    }
                }
            } else {
                sb.append(json[i])
            }
            i++
        }
        
        return Pair(JsonValue.JsonString(sb.toString()), i + 1)
    }
    
    /**
     * 解析 JSON 数字
     */
    private fun parseNumber(json: String, index: Int): Pair<JsonValue, Int> {
        var i = index
        if (json[i] == '-') i++
        
        while (i < json.length && json[i].isDigit()) i++
        if (i < json.length && json[i] == '.') {
            i++
            while (i < json.length && json[i].isDigit()) i++
        }
        if (i < json.length && (json[i] == 'e' || json[i] == 'E')) {
            i++
            if (json[i] == '+' || json[i] == '-') i++
            while (i < json.length && json[i].isDigit()) i++
        }
        
        val numStr = json.substring(index, i)
        return Pair(JsonValue.JsonNumber(numStr.toDouble()), i)
    }
    
    /**
     * 解析 JSON 布尔值
     */
    private fun parseBoolean(json: String, index: Int): Pair<JsonValue, Int> {
        return if (json.startsWith("true", index)) {
            Pair(JsonValue.JsonBoolean(true), index + 4)
        } else {
            Pair(JsonValue.JsonBoolean(false), index + 5)
        }
    }
    
    /**
     * 解析 JSON null
     */
    private fun parseNull(json: String, index: Int): Pair<JsonValue, Int> {
        return Pair(JsonValue.JsonNull, index + 4)
    }
    
    /**
     * 跳过空白字符
     */
    private fun skipWhitespace(json: String, index: Int): Int {
        var i = index
        while (i < json.length && json[i].isWhitespace()) i++
        return i
    }
    
    /**
     * 将 JSON 值转换为字符串
     */
    fun stringify(value: JsonValue): String {
        return when (value) {
            is JsonValue.JsonString -> "\"${value.value.replace("\"", "\\\"")}\""
            is JsonValue.JsonNumber -> value.value.toString()
            is JsonValue.JsonBoolean -> value.value.toString()
            is JsonValue.JsonObject -> {
                "{" + value.value.entries.joinToString(",") { (k, v) ->
                    "\"$k\":${stringify(v)}"
                } + "}"
            }
            is JsonValue.JsonArray -> {
                "[" + value.value.joinToString(",") { stringify(it) } + "]"
            }
            JsonValue.JsonNull -> "null"
        }
    }
    
    /**
     * 获取 JSON 统计信息
     */
    fun getStatistics(json: String): Map<String, Any> {
        val result = parse(json)
        return if (result.isSuccess) {
            val value = result.getOrNull()!!
            mapOf(
                "isValid" to true,
                "type" to value::class.simpleName,
                "length" to json.length,
                "depth" to calculateDepth(value)
            )
        } else {
            mapOf(
                "isValid" to false,
                "error" to (result.exceptionOrNull()?.message ?: "Unknown error")
            )
        }
    }
    
    /**
     * 计算 JSON 深度
     */
    private fun calculateDepth(value: JsonValue): Int {
        return when (value) {
            is JsonValue.JsonObject -> 1 + (value.value.values.maxOfOrNull { calculateDepth(it) } ?: 0)
            is JsonValue.JsonArray -> 1 + (value.value.maxOfOrNull { calculateDepth(it) } ?: 0)
            else -> 0
        }
    }
}

Kotlin 实现的核心特点

Kotlin 实现中的 JSON 解析功能充分利用了 Kotlin 标准库的字符串处理和集合操作能力。使用了密封类来表示不同的 JSON 值类型。递归解析用于处理嵌套结构。

字符串转义处理用于正确解析特殊字符。数字解析支持整数、浮点数和科学计数法。错误处理使用了 Result 类型。

JavaScript 实现

编译后的 JavaScript 代码

// 文件: build/js/packages/kmp_openharmony-js/kotlin/kmp_openharmony.js
// (由 Kotlin 编译器自动生成)

/**
 * JsonParser 类的 JavaScript 版本
 * 通过 Kotlin/JS 编译器从 Kotlin 源代码生成
 */
class JsonParser {
  /**
   * 解析 JSON 字符串
   * @param {string} json - JSON 字符串
   * @returns {Object} 解析结果
   */
  parse(json) {
    try {
      const result = JSON.parse(json);
      return { success: true, value: result };
    } catch (e) {
      return { success: false, error: e.message };
    }
  }

  /**
   * 将对象转换为 JSON 字符串
   * @param {*} value - 要序列化的值
   * @returns {string} JSON 字符串
   */
  stringify(value) {
    try {
      return JSON.stringify(value);
    } catch (e) {
      return null;
    }
  }

  /**
   * 获取 JSON 统计信息
   * @param {string} json - JSON 字符串
   * @returns {Object} 统计信息
   */
  getStatistics(json) {
    try {
      const parsed = JSON.parse(json);
      return {
        isValid: true,
        type: Array.isArray(parsed) ? 'array' : typeof parsed,
        length: json.length,
        depth: this.calculateDepth(parsed)
      };
    } catch (e) {
      return {
        isValid: false,
        error: e.message
      };
    }
  }

  /**
   * 计算 JSON 深度
   * @param {*} value - JSON 值
   * @returns {number} 深度
   */
  calculateDepth(value) {
    if (typeof value !== 'object' || value === null) {
      return 0;
    }

    if (Array.isArray(value)) {
      return 1 + Math.max(...value.map(v => this.calculateDepth(v)), 0);
    }

    const depths = Object.values(value).map(v => this.calculateDepth(v));
    return 1 + Math.max(...depths, 0);
  }

  /**
   * 验证 JSON 格式
   * @param {string} json - JSON 字符串
   * @returns {boolean} 是否有效
   */
  isValidJson(json) {
    try {
      JSON.parse(json);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * 格式化 JSON 字符串
   * @param {string} json - JSON 字符串
   * @param {number} indent - 缩进空格数
   * @returns {string} 格式化后的 JSON
   */
  formatJson(json, indent = 2) {
    try {
      const parsed = JSON.parse(json);
      return JSON.stringify(parsed, null, indent);
    } catch (e) {
      return json;
    }
  }
}

JavaScript 实现的特点

JavaScript 版本完全由 Kotlin/JS 编译器自动生成,确保了与 Kotlin 版本的行为完全一致。JavaScript 的原生 JSON 对象提供了强大的 JSON 处理能力。

JSON.parse 用于解析。JSON.stringify 用于序列化。递归函数用于计算深度。

ArkTS 调用代码

OpenHarmony 应用集成

// 文件: kmp_ceshiapp/entry/src/main/ets/pages/JsonParserPage.ets

import { JsonParser } from '../../../../../../../build/js/packages/kmp_openharmony-js/kotlin/kmp_openharmony';

@Entry
@Component
struct JsonParserPage {
  @State selectedOperation: string = 'parse';
  @State inputJson: string = '';
  @State result: string = '';
  @State resultTitle: string = '';

  private parser = new JsonParser();

  private operations = [
    { name: '📖 解析', value: 'parse' },
    { name: '📝 序列化', value: 'stringify' },
    { name: '✓ 验证', value: 'validate' },
    { name: '📊 统计', value: 'statistics' },
    { name: '✨ 格式化', value: 'format' },
    { name: '📈 深度', value: 'depth' },
    { name: '🔍 分析', value: 'analyze' },
    { name: '📋 报告', value: 'report' }
  ];

  build() {
    Column() {
      // 标题
      Text('📄 JSON解析库示例')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .width('100%')
        .padding(20)
        .backgroundColor('#1A237E')
        .textAlign(TextAlign.Center)

      Scroll() {
        Column() {
          // 操作选择
          Column() {
            Text('选择操作')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')
              .margin({ bottom: 12 })

            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.operations, (op: { name: string; value: string }) => {
                Button(op.name)
                  .layoutWeight(1)
                  .height(40)
                  .margin({ right: 8, bottom: 8 })
                  .backgroundColor(this.selectedOperation === op.value ? '#1A237E' : '#E0E0E0')
                  .fontColor(this.selectedOperation === op.value ? '#FFFFFF' : '#333333')
                  .fontSize(11)
                  .onClick(() => {
                    this.selectedOperation = op.value;
                    this.result = '';
                    this.resultTitle = '';
                  })
              })
            }
            .width('100%')
          }
          .width('95%')
          .margin({ top: 16, left: '2.5%', right: '2.5%', bottom: 16 })
          .padding(12)
          .backgroundColor('#FFFFFF')
          .borderRadius(6)

          // 输入区域
          Column() {
            Text('输入 JSON')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')
              .margin({ bottom: 8 })

            TextInput({ placeholder: '输入 JSON 数据', text: this.inputJson })
              .onChange((value) => this.inputJson = value)
              .width('100%')
              .height(120)
              .padding(12)
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
              .fontSize(12)
          }
          .width('95%')
          .margin({ left: '2.5%', right: '2.5%', bottom: 16 })
          .padding(12)
          .backgroundColor('#FFFFFF')
          .borderRadius(6)

          // 操作按钮
          Row() {
            Button('✨ 处理')
              .layoutWeight(1)
              .height(44)
              .backgroundColor('#1A237E')
              .fontColor('#FFFFFF')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .borderRadius(6)
              .onClick(() => this.executeOperation())

            Blank()
              .width(12)

            Button('🔄 清空')
              .layoutWeight(1)
              .height(44)
              .backgroundColor('#F5F5F5')
              .fontColor('#1A237E')
              .fontSize(14)
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
              .onClick(() => {
                this.inputJson = '';
                this.result = '';
                this.resultTitle = '';
              })
          }
          .width('95%')
          .margin({ left: '2.5%', right: '2.5%', bottom: 16 })

          // 结果显示
          if (this.resultTitle) {
            Column() {
              Text(this.resultTitle)
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .fontColor('#FFFFFF')
                .width('100%')
                .padding(12)
                .backgroundColor('#1A237E')
                .borderRadius(6)
                .textAlign(TextAlign.Center)
                .margin({ bottom: 12 })

              Scroll() {
                Text(this.result)
                  .fontSize(12)
                  .fontColor('#333333')
                  .fontFamily('monospace')
                  .textAlign(TextAlign.Start)
                  .width('100%')
                  .padding(12)
                  .selectable(true)
              }
              .width('100%')
              .height(300)
              .backgroundColor('#F9F9F9')
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
            }
            .width('95%')
            .margin({ left: '2.5%', right: '2.5%', bottom: 16 })
            .padding(12)
            .backgroundColor('#FFFFFF')
            .borderRadius(6)
          }
        }
        .width('100%')
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  private executeOperation() {
    const sampleJson = '{"name":"John","age":30,"city":"New York","hobbies":["reading","coding"]}';
    const inputData = this.inputJson || sampleJson;

    try {
      switch (this.selectedOperation) {
        case 'parse':
          const parseResult = this.parser.parse(inputData);
          this.resultTitle = '📖 解析结果';
          if (parseResult.success) {
            this.result = JSON.stringify(parseResult.value, null, 2);
          } else {
            this.result = `解析失败: ${parseResult.error}`;
          }
          break;

        case 'stringify':
          const obj = { name: 'Alice', age: 25, active: true };
          const stringified = this.parser.stringify(obj);
          this.resultTitle = '📝 序列化结果';
          this.result = stringified || '序列化失败';
          break;

        case 'validate':
          const isValid = this.parser.isValidJson(inputData);
          this.resultTitle = '✓ 验证结果';
          this.result = `JSON 格式: ${isValid ? '有效' : '无效'}`;
          break;

        case 'statistics':
          const stats = this.parser.getStatistics(inputData);
          this.resultTitle = '📊 统计信息';
          this.result = `有效性: ${stats.isValid}\n类型: ${stats.type}\n长度: ${stats.length} 字符\n深度: ${stats.depth}`;
          break;

        case 'format':
          const formatted = this.parser.formatJson(inputData, 2);
          this.resultTitle = '✨ 格式化结果';
          this.result = formatted;
          break;

        case 'depth':
          const stats2 = this.parser.getStatistics(inputData);
          this.resultTitle = '📈 JSON 深度';
          this.result = `JSON 深度: ${stats2.depth}\n深度表示嵌套层级数`;
          break;

        case 'analyze':
          const stats3 = this.parser.getStatistics(inputData);
          this.resultTitle = '🔍 详细分析';
          this.result = `有效性: ${stats3.isValid}\n类型: ${stats3.type}\n字符长度: ${stats3.length}\n嵌套深度: ${stats3.depth}`;
          break;

        case 'report':
          const stats4 = this.parser.getStatistics(inputData);
          this.resultTitle = '📋 分析报告';
          let report = 'JSON 分析报告\n' + '='.repeat(40) + '\n';
          report += `格式有效: ${stats4.isValid}\n`;
          report += `数据类型: ${stats4.type}\n`;
          report += `内容长度: ${stats4.length} 字符\n`;
          report += `嵌套深度: ${stats4.depth} 层\n`;
          this.result = report;
          break;
      }
    } catch (e) {
      this.resultTitle = '❌ 处理出错';
      this.result = `错误: ${e}`;
    }
  }
}

ArkTS 集成的关键要点

在 OpenHarmony 应用中集成 JSON 解析工具库需要考虑多种 JSON 操作和用户体验。我们设计了一个灵活的 UI,能够支持不同的 JSON 处理操作。

操作选择界面使用了 Flex 布局和 FlexWrap 来实现响应式的按钮排列。输入区域使用了较大的高度以容纳多行 JSON 内容。

结果显示使用了可选择的文本,这样用户可以轻松复制处理结果。对于不同的操作,我们显示了相应的 JSON 处理信息。

工作流程详解

JSON 解析的完整流程

  1. 操作选择: 用户在 ArkTS UI 中选择要执行的 JSON 操作
  2. 数据输入: 用户输入要处理的 JSON 数据
  3. 处理执行: 调用 JsonParser 的相应方法
  4. 结果展示: 将处理结果显示在 UI 中

跨平台一致性

通过 KMP 技术,我们确保了在所有平台上的行为一致性。无论是在 Kotlin/JVM、Kotlin/JS 还是通过 ArkTS 调用,JSON 处理的逻辑和结果都是完全相同的。

实际应用场景

API 通信

在 API 通信中,需要解析服务器返回的 JSON 数据。这个工具库提供了完整的 JSON 解析功能。

数据存储

在本地存储中,需要将对象转换为 JSON 格式。这个工具库提供了高效的序列化能力。

配置管理

在配置管理中,需要解析 JSON 配置文件。这个工具库提供了配置处理功能。

数据交换

在系统间数据交换中,需要统一的 JSON 格式。这个工具库提供了标准化的处理方法。

性能优化

缓存解析结果

在频繁进行相同的 JSON 解析时,可以缓存解析结果以避免重复计算。

流式处理

在处理大型 JSON 文件时,应该考虑使用流式处理的方式以提高效率。

安全性考虑

输入验证

在处理用户输入的 JSON 时,应该进行验证以确保数据的有效性。

类型检查

在进行类型转换时,应该进行严格的类型检查以防止错误。

总结

这个 KMP OpenHarmony JSON 解析库示例展示了如何使用现代的跨平台技术来处理常见的 JSON 处理任务。通过 Kotlin Multiplatform 技术,我们可以在一个地方编写业务逻辑,然后在多个平台上使用。

JSON 处理是应用开发中的重要功能。通过使用这样的工具库,开发者可以快速、可靠地处理各种 JSON 操作,从而提高开发效率和应用的数据处理能力。

在实际应用中,建议根据具体的需求进行定制和扩展,例如添加更复杂的 JSON 查询功能、实现更全面的验证功能等高级特性。同时,定期进行性能测试和优化,确保应用在处理大量 JSON 数据时仍然保持良好的性能。欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐