Skip to content

bnayae/Bnaya.Extensions.Json

Repository files navigation

Bnaya Json Extensions

Build & Deploy NuGet

NuGet

codecov

Functionality of this library includes:


ToEnumerable

Enumerate over json elements.

Useful for fetching selected parts of the json

Path based enumeration

Rely on path convention:

json.ToEnumerable(/path convention/);

Json
{
  "friends": [
    {
      "name": "Yaron",    
      "id": 1
    },
    {
      "name": "Aviad",   
      "id": 2
    }
  ]
}
Sample: `friends.[].name` or `friends.*.name`
var items = source.ToEnumerable("friends.[].name");

OR

var items = source.ToEnumerable("friends.*.name");

RESULT

["Yaron", "Aviad"]
Sample: `friends.[0].name`
var items = source.ToEnumerable("friends.[0].name");

RESULT

["Yaron"]
Sample: `friends.[0].*`
var items = source.ToEnumerable("friends.[0].*");

RESULT

["Yaron",1]

See: YieldWhen_Path_Test in the source code

Predicate based enumeration

Yield element according to predicate and onMatch delegates.

Sample:

Json
{
    "projects": [ {
        "key": "cloud-d",
        "duration": 8
    }, {
    "users": [{
        "rank": {
            "job": 10,
            "relationship": {
                "projects": [
                    { "key": "cloud-d", "team": 5 },
                    { "key": "cloud-x", "team": 32 }
                ]
            }
        },
    }]
}
Code
TraverseInstruction Predicate(JsonElement current, IImmutableList<string> breadcrumbs)
{
    if (breadcrumbs.Count < 4)
        return ToChildren;

    if (breadcrumbs[^4] == "relationship" &&
        breadcrumbs[^3] == "projects" &&
        breadcrumbs[^1] == "key")
    {
        return new TraverseInstruction(Stop, TraverseAction.Take);
    }

    return ToChildren;
}
var items = source.ToEnumerable(Predicate);

Filter

Reduce (or modify) a json

Json

JSON:

{
  "A": 10,
  "B": [
    { "Val": 40 },
    { "Val": 20 },
    { "Factor": 20 }
  ],
  "C": [0, 25, 50, 100 ],
  "Note": "Re-shape json"
}
Code
TraverseInstruction Strategy(
                JsonElement e,
                IImmutableList<string> breadcrumbs)
{ 
    if (e.ValueKind == JsonValueKind.Number)
    {
        var val = e.GetInt32();
        if (val > 30)
            return TraverseInstruction.TakeOrReplace;
        return TraverseInstruction.SkipToSibling;
    }
    if (e.ValueKind == JsonValueKind.Array || e.ValueKind == JsonValueKind.Object)
        return TraverseInstruction.ToChildren;
    return TraverseInstruction.TakeOrReplace;
}

JsonElement target = source.Filter(Strategy);

Will result in:

{
  "B": [ { "Val": 40 }],
  "C": [ 50, 100 ],
  "Note": "Re-shape json"
}

Keep

Path based Filter

Json
``` json { "A": 10, "B": [ { "Val": 40 }, { "Val": 20 }, { "Factor": 20 } ], "C": [0, 25, 50, 100 ], "Note": "Re-shape json" } ```
Sample: B.*.val
var target = source.Keep("B.*.val");

RESULT

{"B":[{"Val":40},{"Val":20}]}
Sample: B.[]
var target = source.Keep("B.[]");

RESULT

{"B":[{"Val":40},{"Val":20},{"Factor":20}]}
Sample: B.[1].val
var target = source.Keep("B.[].Factor");

RESULT

{"B":[{"Factor":20}]}
Sample: B.[1].val
var target = source.Keep("B.[1].val");

RESULT

{"B":[{"Val":20}]}

Remove

Remove elements from the json.

Json
{
  "A": 10,
  "B": [
    { "Val": 40 },
    { "Val": 20 },
    { "Factor": 20 }
  ],
  "C": [0, 25, 50, 100 ],
  "Note": "Re-shape json"
}
Sample: B.[]
var target = source.Remove("B.[]");

RESULT

{"A":10,"C":[0,25,50,100],"Note":"Re-shape json"}
Sample: B.*.val
var target = source.Remove("B.*.val");

RESULT

{"A":10,"B":[{"Factor":20}],"C":[0,25,50,100],"Note":"Re-shape json"}
Sample: B.[1]
var target = source.Remove("B.[1]");

RESULT

{"A":10,"B":[{"Val":40},{"Factor":20}],"C":[0,25,50,100],"Note":"Re-shape json"}
Sample: B
var target = source.Remove("B");

RESULT

{"A":10,"C":[0,25,50,100],"Note":"Re-shape json"}
Sample: B.[1].val
var target = source.Remove("B.[1].val");

RESULT

{"A":10,"B":[{"Val":40},{"Val":20},{"Factor":20}],"C":[0,25,50,100],"Note":"Re-shape json"}

TryAddProperty

Try to add property if missing.

Sample 1
{ "A": 0, "B": 0 }
source.RootElement.TryAddProperty("C", 1);

Result in:

{ "A": 0, "B": 0, "C": 1 }
Sample 2
{ "A": 0, "B": 0, "C": 0 }
source.RootElement.TryAddProperty("C", 1);

Result in:

{ "A": 0, "B": 0, "C": 0 }
Sample: 3
{ "A": 0, "B": 0, "C": null }
var source = JsonDocument.Parse(json);
source.RootElement.TryAddProperty("C", 1);

Result in:

{ "A": 0, "B": 0, "C": 1 }

Unless sets the options not to ignore null

Sample: ignored null

Ignored null

var options = new JsonPropertyModificatonOpions
{
    IgnoreNull = false
};
var source = JsonDocument.Parse(json);
source.RootElement.TryAddProperty("C", 1);

Result in:

{ "A": 0, "B": 0, "C": null }
Sample: Changing property within a path

Changing property within a path

{
  "X": {
    "Y": {
    	"A": 0,
    	"B": 0
    }
  },
  "Y": { "Q": 2 }
}
source.RootElement.TryAddProperty("X.Y", "C", 1);

Result in:

{
  "X": {
      "Y": {
          "A": 0,
          "B": 0,  
          "C": 1
      }
  },
  "Y": { "Q": 2 }
}

TryGetValue

Try to get a value within a path

Json
{
  "B": {
    "B1": ["Very", "Cool"],
    "B2": {
        "B21": {
          "B211": "OK"
        },
        "B22": 22,   
        "B23": true,
        "B24": 1.8,
        "B25": "2007-09-01T10:35:01",
        "B26": "2007-09-01T10:35:01+02"
    }
  }
}
Sample: B.B1
source.TryGetValue(out JsonElement value, "B.B1")

Result in:

["Very","Cool"]
Sample: B.B1.*
source.TryGetValue(out JsonElement value, "B.B1.*")

Result in:

Very

TryGet...

Try to get a value within a path.

Json
{
  "B": {
    "B1": ["Very", "Cool"],
    "B2": {
        "B21": {
          "B211": "OK"
        },
        "B22": 22,   
        "B23": true,
        "B24": 1.8,
        "B25": "2007-09-01T10:35:01",
        "B26": "2007-09-01T10:35:01+02"
    }
  }
}
Sample: String
source.TryGetString(out JsonElement value, "B.B2.*.B211")

Result in: OK

Sample: DateTiemOffset
source.TryGetValue(out JsonElement value, "B.*.B26")

Result in: 2007-09-01T10:35:01+02

Sample: Double
source.TryGetNumber(out double value, "B.B2.B24")

Result in: 1.8


Merge

Merging 2 or more json. The last json will override previous on conflicts

Sample: 1

Source: { "A": 1 } , Merged: { "B": 2 }

var target = source.Merge(merged);

Result in: {"A":1,"b":2}

Sample: 2

Source: { "A": 1 } , Merged: {"B":2,"C":3}

var target = source.Merge(merged);

Result in: { "A":1, "B":2, "C":3 }

Sample:

Source: { "A": 1 } , Merged1: {"B":2} , Merged2: {"C":3}

var target = source.Merge(merged1, merged2);

Result in: { "A":1, "B":2, "C":3 }

Sample:

Source: { "A": 1 }

var target = source.MergeObject(new { b = 2 });

Result in: {"A":1, "B":2}

Merge Into

Merging json into specific path of a source json.

The last json will override any previous one in case of a conflicts

Sample: 1

Source

{ "A": 1, "B": { "B1":[1, 2, 3] }, "C": { "D": { "X":1, "Y":2 } } }
var target = source.MergeInto("C.D.X", 100);

Result in: { "A": 1, "B": { "B1":[1, 2, 3] }, "C": { "D": { "X":100, "Y":2 } } }

Sample: 2

Source

{ "A": 1, "B": { "B1":[1, 2, 3] }, "C": { "D": { "X":1, "Y":2 } } }

Merged

{ "Z": 3}
var target = source.MergeInto("C.D", merged);

Result in: { "A": 1, "B": { "B1":[1, 2, 3] }, "C": { "D": { "X":1, "Y":2, "Z": 3 } } }

Sample: 3

Source

{'A':1,'B': {'B1':1}}

Merged

{'B1':3, 'C':[1,2,3]}
var target = source.MergeInto("B", merged);

Result in: {'A':1, 'B':{'B1':3, 'C':[1,2,3]}}

Sample: 4

Source

{'A':1,'B':{'B1':[1,2,3]}}
var target = source.MergeInto("B.B1.[1]", 5);

Result in: {'A':1, 'B':{'B1':[1,5,3]}}

Serialization

ToJson

Convert .NET object into JsonElement.

var entity = new Entity(12, new BEntity("Z"));
JsonElement json = entity.ToJson();
var arr = new []{ 1, 2, 3 };
JsonElement json = arr.ToJson();

AsString

Convert JsonElement to string

JsonElement json = ...;
string compact = json.AsString();
string indented = json.AsIndentString();
string raw = json.GetRawText(); // same as json.AsIndentString();

ToStream

Convert JsonElement to stream

var json = JsonDocument.Parse(JSON);
var srm = json.ToStream() as MemoryStream;
string result = Encoding.UTF8.GetString(srm.ToArray()) ;

Looking for other extensions?

Check the following

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages