c#을 사용한 일반적인 Json 평탄화
데이터 테이블로 변환하고 c#을 사용하여 데이터 그리드에 바인딩할 수 있도록 일반적으로 json을 평탄하게 만들고 싶다.
몇 단계까지 내려갈지 모르는데, 어떻게 하는 것이 가장 좋은 방법일까요?
예.
{"멘테이션 ID": 4,"policyid": 1,"filename" : "000000-0000-0000-0000-00000000","번호": "1234567890","ampm" : "false","날짜" : "2015-09-08"T00:00:00","차량": {"id": 1,"filename" : "000000-0000-0000-0000-00000000","make" : null,"model" : null},"실행": {"paramid" : "1","name" : "installer 1","연락처": "qwerty","qascore" : "0","address1" : "qwerty","address2": "qwerty","address3": null,"address4": null,"city" : "qwertu","quertu", "quertu","우편번호" : "asdfghj","국가": "GB","email" : "asdfghj","web": "asdfghjk","false" : false},'설치' : [{"installationid" : 6,"설치 상태": {"installationstatusid": 4,"installation status" : "FAIL"},"isactive" : true},{"installationid" : 7,"설치 상태": {"installationstatusid" : 1,'설치 상태' : '신규'},"isactive" : false}],"false" : false}
installations.1.installationid가 아닌 installationid1을 취득할 수 있도록 (변환한 데이터 테이블을 통해 반복할 수 있을 것 같습니다.)
데이터 테이블을 그리드에 표시하기 때문에 열 이름을 친숙하게 유지하고 싶습니다.
Json을 사용할 수 있습니다.데이터를 구조체로 구문 분석하는 Net의 LINQ-to-JSON API.여기서 재귀적 도우미 방법을 사용하여 구조체를 걷고 평탄하게 만들 수 있습니다.Dictionary<string, object>
여기서 키는 원래 JSON에서 각 값에 대한 "경로"입니다.이렇게 쓰고 싶어요.
public class JsonHelper
{
public static Dictionary<string, object> DeserializeAndFlatten(string json)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
JToken token = JToken.Parse(json);
FillDictionaryFromJToken(dict, token, "");
return dict;
}
private static void FillDictionaryFromJToken(Dictionary<string, object> dict, JToken token, string prefix)
{
switch (token.Type)
{
case JTokenType.Object:
foreach (JProperty prop in token.Children<JProperty>())
{
FillDictionaryFromJToken(dict, prop.Value, Join(prefix, prop.Name));
}
break;
case JTokenType.Array:
int index = 0;
foreach (JToken value in token.Children())
{
FillDictionaryFromJToken(dict, value, Join(prefix, index.ToString()));
index++;
}
break;
default:
dict.Add(prefix, ((JValue)token).Value);
break;
}
}
private static string Join(string prefix, string name)
{
return (string.IsNullOrEmpty(prefix) ? name : prefix + "." + name);
}
}
이것을 사용하여DeserializeAndFlatten
JSON을 사용한 방법은 다음과 같은 키와 값의 쌍을 얻을 수 있습니다.
appointmentid: 4
policyid: 1
guid: 00000000-0000-0000-0000-000000000000
number: 1234567890
ampm: false
date: 9/8/2015 12:00:00 AM
vehicle.id: 1
vehicle.guid: 00000000-0000-0000-0000-000000000000
vehicle.make:
vehicle.model:
installer.installerid: 1
installer.name: Installer 1
installer.contact: qwerty
installer.qascore: 0
installer.address1: qwerty
installer.address2: qwerty
installer.address3:
installer.address4:
installer.city: qwertyu
installer.county: qwertyu
installer.postcode: asdfghj
installer.country: GB
installer.email: asdfghj
installer.web: asdfghjk
installer.archived: False
installations.0.installationid: 6
installations.0.installationstatus.installationstatusid: 4
installations.0.installationstatus.installationstatus: FAIL
installations.0.isactive: True
installations.1.installationid: 7
installations.1.installationstatus.installationstatusid: 1
installations.1.installationstatus.installationstatus: NEW
installations.1.isactive: False
archived: False
키를 좀 더 인간답게 만들고 싶다면, 작은 끈 조작으로 키를 자를 수 있습니다.아마 이런 식일 거예요.
var dict = JsonHelper.DeserializeAndFlatten(json);
foreach (var kvp in dict)
{
int i = kvp.Key.LastIndexOf(".");
string key = (i > -1 ? kvp.Key.Substring(i + 1) : kvp.Key);
Match m = Regex.Match(kvp.Key, @"\.([0-9]+)\.");
if (m.Success) key += m.Groups[1].Value;
Console.WriteLine(key + ": " + kvp.Value);
}
대신 다음과 같은 출력을 얻을 수 있습니다.
appointmentid: 4
policyid: 1
guid: 00000000-0000-0000-0000-000000000000
number: 1234567890
ampm: false
date: 9/8/2015 12:00:00 AM
id: 1
guid: 00000000-0000-0000-0000-000000000000
make:
model:
installerid: 1
name: Installer 1
contact: qwerty
qascore: 0
address1: qwerty
address2: qwerty
address3:
address4:
city: qwertyu
county: qwertyu
postcode: asdfghj
country: GB
email: asdfghj
web: asdfghjk
archived: False
installationid0: 6
installationstatusid0: 4
installationstatus0: FAIL
isactive0: True
installationid1: 7
installationstatusid1: 1
installationstatus1: NEW
isactive1: False
archived: False
이 의 동일한 문맥이 을 알 수.예를 들어, 현재 2개의 동일한 콘텍스트가 있는 것을 알 수 있습니다.archived
( 「JSON」, 「JSON」, 「JSON」, 「JSON」, 「Keys」, 「Keys」)에되어 있었습니다.installer.archived
★★archived
는, 그 해 낼 필요가 ). 이 문제에 대해서는, 스스로 대처해 나갈 필요가 있습니다.
바이올린: https://dotnetfiddle.net/gzhWHk
라이브러리 Json 사용.Net JSONPath를 사용할 수 있습니다.$..*
JSON 구조의 모든 멤버를 가져오고 하위 항목이 없는 멤버를 필터링하여 컨테이너 속성을 건너뜁니다.
예.
var schemaObject = JObject.Parse(schema);
var values = schemaObject
.SelectTokens("$..*")
.Where(t => !t.HasValues)
.ToDictionary(t => t.Path, t => t.ToString());
뉴턴소프트의 Json을 사용한 또 다른 변종입니다.루트 오브젝트의 NET LINQ to JSON (동일하게 할 수 있습니다)JArray
: 타타 ) ) :
var flattened = JObject.Parse(json)
.Descendants()
.OfType<JValue>()
.ToDictionary(jv => jv.Path, jv => jv.ToString())
해결책도 찾아봤고 그걸로 해결됐죠결과 세트에 새로운 C#7 Tupels를 사용.다른 경량 솔루션을 가지고 계신 분이 있다면, 저는 관심이 있습니다.-)
async Task Main()
{
var jsonUsers = await new HttpClient().GetStringAsync(@"https://jsonplaceholder.typicode.com/users");
foreach (var flattedChild in GetFlatJsonChilds(JToken.Parse(jsonUsers)))
Console.WriteLine($"{flattedChild.path}: {flattedChild.value}");
}
IEnumerable<(string path, string value)> GetFlatJsonChilds(JToken token)
{
foreach (var child in token.Children())
{
if(token.Type != JTokenType.Array &&token.Children().First().Type != JTokenType.Property && !child.Children().Any())
yield return (child.Path, child.ToString());
foreach(var childChild in GetFlatJsonChilds(child))
yield return childChild;
}
}
https://jsonplaceholder.typicode.com/users의 결과:
[0].id: 1
[0].name: Leanne Graham
[0].username: Bret
[0].email: Sincere@april.biz
[0].address.street: Kulas Light
[0].address.suite: Apt. 556
[0].address.city: Gwenborough
[0].address.zipcode: 92998-3874
[0].address.geo.lat: -37.3159
[0].address.geo.lng: 81.1496
[0].phone: 1-770-736-8031 x56442
[0].website: hildegard.org
[0].company.name: Romaguera-Crona
[0].company.catchPhrase: Multi-layered client-server neural-net
[0].company.bs: harness real-time e-markets
[1].id: 2
[1].name: Ervin Howell
[1].username: Antonette
[1].email: Shanna@melissa.tv
[1].address.street: Victor Plains
[1].address.suite: Suite 879
[1].address.city: Wisokyburgh
[1].address.zipcode: 90566-7771
[1].address.geo.lat: -43.9509
[1].address.geo.lng: -34.4618
[1].phone: 010-692-6593 x09125
[1].website: anastasia.net
[1].company.name: Deckow-Crist
[1].company.catchPhrase: Proactive didactic contingency
[1].company.bs: synergize scalable supply-chains
[2].id: 3
[2].name: Clementine Bauch
[2].username: Samantha
[2].email: Nathan@yesenia.net
[2].address.street: Douglas Extension
[2].address.suite: Suite 847
[2].address.city: McKenziehaven
[2].address.zipcode: 59590-4157
[2].address.geo.lat: -68.6102
[2].address.geo.lng: -47.0653
[2].phone: 1-463-123-4447
[2].website: ramiro.info
[2].company.name: Romaguera-Jacobson
[2].company.catchPhrase: Face to face bifurcated interface
[2].company.bs: e-enable strategic applications
[3].id: 4
[3].name: Patricia Lebsack
[3].username: Karianne
[3].email: Julianne.OConner@kory.org
[3].address.street: Hoeger Mall
[3].address.suite: Apt. 692
[3].address.city: South Elvis
[3].address.zipcode: 53919-4257
[3].address.geo.lat: 29.4572
[3].address.geo.lng: -164.2990
[3].phone: 493-170-9623 x156
[3].website: kale.biz
[3].company.name: Robel-Corkery
[3].company.catchPhrase: Multi-tiered zero tolerance productivity
[3].company.bs: transition cutting-edge web services
[4].id: 5
[4].name: Chelsey Dietrich
[4].username: Kamren
[4].email: Lucio_Hettinger@annie.ca
[4].address.street: Skiles Walks
[4].address.suite: Suite 351
[4].address.city: Roscoeview
[4].address.zipcode: 33263
[4].address.geo.lat: -31.8129
[4].address.geo.lng: 62.5342
[4].phone: (254)954-1289
[4].website: demarco.info
[4].company.name: Keebler LLC
[4].company.catchPhrase: User-centric fault-tolerant solution
[4].company.bs: revolutionize end-to-end systems
[5].id: 6
[5].name: Mrs. Dennis Schulist
[5].username: Leopoldo_Corkery
[5].email: Karley_Dach@jasper.info
[5].address.street: Norberto Crossing
[5].address.suite: Apt. 950
[5].address.city: South Christy
[5].address.zipcode: 23505-1337
[5].address.geo.lat: -71.4197
[5].address.geo.lng: 71.7478
[5].phone: 1-477-935-8478 x6430
[5].website: ola.org
[5].company.name: Considine-Lockman
[5].company.catchPhrase: Synchronised bottom-line interface
[5].company.bs: e-enable innovative applications
[6].id: 7
[6].name: Kurtis Weissnat
[6].username: Elwyn.Skiles
[6].email: Telly.Hoeger@billy.biz
[6].address.street: Rex Trail
[6].address.suite: Suite 280
[6].address.city: Howemouth
[6].address.zipcode: 58804-1099
[6].address.geo.lat: 24.8918
[6].address.geo.lng: 21.8984
[6].phone: 210.067.6132
[6].website: elvis.io
[6].company.name: Johns Group
[6].company.catchPhrase: Configurable multimedia task-force
[6].company.bs: generate enterprise e-tailers
[7].id: 8
[7].name: Nicholas Runolfsdottir V
[7].username: Maxime_Nienow
[7].email: Sherwood@rosamond.me
[7].address.street: Ellsworth Summit
[7].address.suite: Suite 729
[7].address.city: Aliyaview
[7].address.zipcode: 45169
[7].address.geo.lat: -14.3990
[7].address.geo.lng: -120.7677
[7].phone: 586.493.6943 x140
[7].website: jacynthe.com
[7].company.name: Abernathy Group
[7].company.catchPhrase: Implemented secondary concept
[7].company.bs: e-enable extensible e-tailers
[8].id: 9
[8].name: Glenna Reichert
[8].username: Delphine
[8].email: Chaim_McDermott@dana.io
[8].address.street: Dayna Park
[8].address.suite: Suite 449
[8].address.city: Bartholomebury
[8].address.zipcode: 76495-3109
[8].address.geo.lat: 24.6463
[8].address.geo.lng: -168.8889
[8].phone: (775)976-6794 x41206
[8].website: conrad.com
[8].company.name: Yost and Sons
[8].company.catchPhrase: Switchable contextually-based project
[8].company.bs: aggregate real-time technologies
[9].id: 10
[9].name: Clementina DuBuque
[9].username: Moriah.Stanton
[9].email: Rey.Padberg@karina.biz
[9].address.street: Kattie Turnpike
[9].address.suite: Suite 198
[9].address.city: Lebsackbury
[9].address.zipcode: 31428-2261
[9].address.geo.lat: -38.2386
[9].address.geo.lng: 57.2232
[9].phone: 024-648-3804
[9].website: ambrose.net
[9].company.name: Hoeger LLC
[9].company.catchPhrase: Centralized empowering task-force
[9].company.bs: target end-to-end models
직렬화를 해제한 다음 LINQ가 평탄화를 선택합니다.아직 언급하지 않으셨으니, 모든 예약 및 설치 정보를 특정 설치와 동일한 레코드에 저장하길 원하십니까?
초기 아이디어는 JSON에 정적 스키마를 삽입할 필요가 없도록 다이내믹스를 활용하는 것입니다.JSON 스키마로서 기능할 수 있는 스태틱타입이 이미 있는 경우 다이내믹스(및 그 모든 것을 수반)를 회피할 수 있습니다.다음은 JSON을 사용한 수업 예시입니다.NET - 내 생각을 설명한다.
public class DeserializeAndFlatten
{
public dynamic ParseJson()
{
var appointment = JObject.Parse(JsonData.JSON_TO_PARSE); // <-- replace the constant w/ the real JSON...
// this is where you flatten it all out!
// not going to put all the fields in, that would kill the example, LOL
var installations = appointment["installations"].Select(installation => new
{
appointmentId = appointment["appointmentid"],
policyId = appointment["policyid"],
vehicleId = appointment["vehicle"]["id"],
vehicleMake = appointment["vehicle"]["make"],
vehicleModel = appointment["vehicle"]["model"],
installerId = appointment["installer"]["installerid"],
installerName = appointment["installer"]["name"],
installationId = installation["installationid"],
installationStatus = installation["installationstatus"]["installationstatus"],
installationStatusId = installation["installationstatus"]["installationstatusid"],
}).ToList();
return installations;
}
}
코드를 테스트할 수 있습니다.
static void Main(string[] args)
{
var jsonParser = new DeserializeAndFlatten();
var installations = jsonParser.ParseJson();
// FYI we get back a dynamic listing,
// so intellisense wont work...
foreach (var installation in installations)
{
Console.WriteLine($"appointmentId: {installation.appointmentId}");
Console.WriteLine($"installer: {installation.installerName}");
Console.WriteLine($"installation id: {installation.installationId}");
Console.WriteLine($"status: {installation.installationStatus}");
Console.WriteLine();
}
Console.ReadLine();
}
F#에서도 같은 것이 필요한 경우:
module JsonFlatten =
let Join prefix name =
if String.IsNullOrEmpty(prefix) then name else prefix + "." + name
let rec FillDictionaryFromJToken (dict:Dictionary<string, string>) (token:JToken) (prefix:string) =
match token.Type with
| JTokenType.Object ->
for prop in token.Children<JProperty>() do
FillDictionaryFromJToken dict prop.Value (Join prefix prop.Name)
| JTokenType.Array ->
let mutable index = 0
for value in token.Children() do
FillDictionaryFromJToken dict value (Join prefix (index.ToString()))
index <- index + 1
| _ ->
dict.Add(prefix, sprintf "%A" (token :?> JValue).Value)
let DeserializeAndFlatten(json:string) =
let dict = Dictionary<string, string>()
let token = JToken.Parse(json);
FillDictionaryFromJToken dict token ""
dict
다음은 Cinchoo ETL을 사용하여 JSON을 평평하게 하거나 DataTable로 변환하는 다른 방법입니다.
평탄한 JSON:
using (var r = new ChoJSONReader("*** JSON file path ***"))
{
foreach (var rec in r.Select(f => f.Flatten()))
Console.WriteLine(rec.Dump());
}
JSON에서 DataTable로:
using (var r = new ChoJSONReader("*** JSON file path ***"))
{
var dt = r.AsDataTable();
Console.WriteLine(dt.DumpAsJson());
}
오늘 키/값 목록에 일부 JSON을 로드해야 하므로 의 Microsoft 구성을 사용하기로 결정했습니다.「Microsoft」의 NET.내선번호설정":
ConfigurationBuilder jsonConfigurationBuilder = new ConfigurationBuilder();
jsonConfigurationBuilder.AddJsonFile(fileName, false, false);
IConfiguration jsonConfiguration = jsonConfigurationBuilder.Build();
이제 JSON이 로드되어 IConfiguration으로 파셋되고 다음 방법을 사용하여 키/값 쌍 목록에 쉽게 넣을 수 있습니다.
public IEnumerable<KeyValuePair<String, Object>> GetConfigurationEnumerator(IConfiguration configuration) {
// Get the configuration child sections into a stack.
Stack<IConfigurationSection> configurationSectionStack = new Stack<IConfigurationSection>();
foreach (IConfigurationSection configurationSection in configuration.GetChildren()) {
configurationSectionStack.Push(configurationSection);
}
// Return a key/value pair for each configuration section, and add additional child sections to the stack.
while (configurationSectionStack.Count > 0) {
// Get the configuration section.
IConfigurationSection configurationSection = configurationSectionStack.Pop();
// eturn a key/value pair.
yield return new KeyValuePair<String, Object>(configurationSection.Path, configurationSection.Value);
// Add the child sections to the stack.
foreach (IConfigurationSection configurationSectionChild in configurationSection.GetChildren()) {
configurationSectionStack.Push(configurationSectionChild);
}
}
} // GetConfigurationEnumerator
그리고 콘솔에 결과를 기록합니다.
foreach (KeyValuePair<String, Object> value in GetConfigurationEnumerator(jsonConfiguration)) {
Console.WriteLine($" {value.Key} == {value.Value}");
}
결과는 다음과 같습니다. "level0:level1:level2 == this is the value"
언급URL : https://stackoverflow.com/questions/32782937/generically-flatten-json-using-c-sharp
'programing' 카테고리의 다른 글
.py 파일의 MIME 유형은 무엇입니까? (0) | 2023.03.23 |
---|---|
gson을 사용한 객체의 특정 JSON 필드 역직렬화 (0) | 2023.03.18 |
Angular를 사용하여 해결된 약속 즉시 반환JS (0) | 2023.03.18 |
$location을 사용합니다.search(): 늘일 때 URL에서 파라미터를 삭제하는 방법 (0) | 2023.03.18 |
ios Swift에서 JSON을 문자열로 변환하는 방법 (0) | 2023.03.18 |