这是一个用于 Swift 的 JSON Patch 库,具有符合人体工程学的 DSL。它基于 Patchouli Core 引擎构建,并使用 JSONPatch 库来执行补丁。
要通过 SPM 安装,请添加对 https://github.com/alexhunsley/patchouli-jsonpatch
的依赖项。
或者,想在 Playground 中体验 PatchouliJSON,请访问 https://swiftpackageindex.cn/alexhunsley/patchouli-jsonpatch 并选择 “Try in a playground”。
import PatchouliJSON
// Use the DSL to construct a patch on a file's JSON content.
// This step doesn't do the actual patching!
let patchedJSONContent: PatchedJSON = Content(fileURL: someJSONFileURL) {
Add(address: "/users/-", jsonContent: "alex")
Add(address: "/users/-", jsonContent: [1, "hi", 5.0])
// note: please use `null` (and never `nil`) to represent JSON's `null`
Add(address: "/users/-", jsonContent: null)
Remove(address: "/temp/log")
Replace(address: "/user_type", jsonContent: "admin")
Move(fromAddress: "/v1/last_login", toAddress: "/v2/last_login")
Copy(fromAddress: "/v1/login_count", toAddress: "/v2/login_count")
Test(address: "/magic_string", jsonContent: "0xdeadbeef")
}
// execute the patch
let resultJSONContent: JSONContent = try content.reduced()
// Get the result in various forms
let jsonData = try dataResult.data()
let jsonString = try dataResult.string() // defaults to UTF8
let jsonStringUTF16 = try dataResult.string(encoding: utf16)
您还可以从 Bundle 中获取 JSON 内容
// loads User.json from the main bundle
let patchedJSONContent: PatchedJSON = Content(resource: "User", bundle: Bundle.main) {
Add(address: "/users/-", jsonContent: "alex")
...
您可以使用字符串字面量作为您的源 json(假设为 utf8 编码)
let patchedJSONContent: PatchedJSON = Content(string:
"""
{ "greet": "Hello", "bye": "auf wiedersehen", "users": [] }
"""
) {
Add(address: "/users/-", jsonContent: "alex")
...
您还可以使用一个空的 JSON 对象或数组作为您的起点
let patchedEmptyObject = EmptyJSONObject {
Add(address: "/asdf", jsonContent: "Hello")
}
let patchedEmptyArray1 = EmptyJSONArray {
Add(address: "/-", jsonContent: "xyz")
Add(address: "/-", jsonContent: "abc")
}
您可以像 SwiftUI 的 @ViewBuilder
一样使用 @JSONPatchListBuilder
来分解您的补丁声明
@JSONPatchListBuilder
func builderFunc(name: String) -> JSONPatchList {
Add(address: "/asdf", jsonContent: "Hello \(name)")
Add(address: "/qwer", jsonContent: "Bye \(name)")
}
@JSONPatchListBuilder
var builderVar: JSONPatchList {
Add(address: "/addr1", jsonContent: "Hello")
Add(address: "/addr2", jsonContent: "Bye")
builderFunc(name: "boo")
}
func useBuilderHelpers() throws {
let patchedJSONContent = Content(JSONPatchType.emptyObjectContent) {
builderFunc(name: "fred")
builderVar
}
如果您想只声明一次补丁列表以便在多个不同的 JSON 上使用,这将特别有用。
DSL 可以处理 if
, if-else
, for
, for-in
和可选值。例如:
let patchedJSONContent: PatchedJSON = Content(fileURL: someJSONFileURL) {
for index in 0...5 {
if someCheck(index) {
Add(address: "/abc", jsonContent: "\(index)")
}
if someCondition {
Add(address: "/cde", jsonContent: "\(index)")
} else {
Remove(address: "/cde")
}
}
for user in users {
Add(address: "/usernames/-", jsonContent: "\(user.username)")
}
}
DSL 可以处理嵌套,这意味着您可以拥有补丁中的补丁
let patchedJSONContent: PatchedJSON = Content(fileURL: jsonFile1URL) {
Add(address: "/some_key", content: Content(fileURL: jsonFile2URL) {
Replace(address: "hello", jsonContent: "friend")
})
Remove(address: "/remove_me")
}
请注意,对于嵌套补丁,最深层的操作首先被解析:在上面的示例中,Replace
补丁应用于 JSON 文件 2 的内容。结果然后被添加到 JSON 文件 1 的内容中的 /some_key
。最后,对我们拥有的内容执行 Remove
操作。
Patchouli JSON 构建于 Patchouli Core 之上,这是一个通用的补丁引擎。您可以使用 Patchouli Core 为其他类型的数据创建补丁程序。
resultbuilder, protocol witness, generics, json, jsonpatch
Copyright 2024 Alex Hunsley
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://apache.ac.cn/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.