안녕하세요 이번 포스트에서는 지난 포스트에서 진행하였던 Web Client & Web Request를 이용해 NEIS 급식 정보를 파싱 해온 것에 대한 모델을 만들고 JsonConvert.DeserializeObject를 이용한 역직렬화(객체화)를 해보도록 하겠습니다. 이번 편은 1편과 이어지는 내용이니 아직 1편을 보지 않으셨다면 1편을 먼저 보고 오시는 것을 추천드립니다.
https://devkyunghoon.tistory.com/3
포스트 🔑 포인트
🚩 1. 파싱 해온 json 데이터의 구조가 어떻게 이루어져 있는지 파악하기
🚩 2. 데이터 구조를 토대로 데이터를 담을 모델 만들어보기
🚩 3. NugetPackage - Newtonsoft.Json의 JsonConvert.DeserializeObject 메서드 이용하기
우선 JSON Visualizer를 통해 간략하게 보도록 하겠습니다. JSON 데이터를 보게 되면 mealServiceDietInfo라는 것이 [0], [1]에 각각 head와 row를 가지고 있습니다. 그리고 그 각각의 아래인 head 아래를 보면 또 [0], [1]에 각각의 Property(속성)에 대한 값들을 가지고 있습니다. 마찬가지로 row를 보면 배열 형태로 상세 정보와 학교 코드, 교육청, 급식 코드, 급식 내용들이 들어가 있는 것을 볼 수 있습니다.
아래의 내용은 실제 디버깅을 통해 찍어본 값입니다. 많이 길어서 급식에 대한 정보는 일부만 가져왔습니다. 아래의 내용을 보시면 자세한 내용을 볼 수 있습니다. head에 대해서 먼저 보겠습니다. head를 보면 크게 list_total_count와 RESULT에 대한 속성을 가지고 있습니다. 그리고 RESULT 안에 CODE와 MESSAGE를 가지고 있는 것을 볼 수 있습니다.
그다음은 row를 보겠습니다. row는 분리되어 가지고 있는 것이 안리 여러 Property가 하나인 배열을 가지고 있는 것을 볼 수 있습니다. 아래의 긴 정보가 하나의 배열의 인자에 들어있는 값들입니다. 즉 저 정보들이 여러 개 있다고 생각하시면 됩니다.
[
{
"head": [
{
"list_total_count": 799
},
{
"RESULT": {
"CODE": "INFO-000",
"MESSAGE": "정상 처리되었습니다."
}
}
]
},
{
"row": [
{
"ATPT_OFCDC_SC_CODE": "D10",
"ATPT_OFCDC_SC_NM": "대구광역시교육청",
"SD_SCHUL_CODE": "7240393",
"SCHUL_NM": "대구소프트웨어고등학교",
"MMEAL_SC_CODE": "1",
"MMEAL_SC_NM": "조식",
"MLSV_YMD": "20190128",
"MLSV_FGR": "130",
"DDISH_NM": "굴소스베이컨볶음밥2.5.6.10.13.<br/>크로크무슈1.2.5.6.10.13.<br/>배추김치(조)9.<br/>초코첵스(쿠키&크림)시리얼+우유2.5.6.13.",
"ORPLC_INFO": "쌀 : 국내산<br/>김치류 : 국내산<br/>고춧가루(김치류) : 국내산<br/>쇠고기(종류) : 국내산(한우)<br/>돼지고기 : 국내산<br/>닭고기 : 국내산<br/>오리고기 : 국내산<br/>양고기 : 국내산<br/>쇠고기 식육가공품 : 국내산<br/>돼지고기 식육가공품 : 국내산<br/>닭고기 식육가공품 : 국내산<br/>오리고기 가공품 : 국내산<br/>양고기 식육가공품 : 국내산<br/>넙치 : 국내산<br/>조피볼락 : 국내산<br/>참돔 : 국내산<br/>미꾸라지 : 국내산<br/>뱀장어 : 국내산<br/>낙지 : 국내산<br/>명태 : 국내산<br/>고등어 : 국내산<br/>갈치 : 국내산<br/>오징어 : 국내산<br/>꽃게 : 국내산<br/>참조기 : 국내산<br/>두부 : 국내산<br/>콩 : 국내산",
"CAL_INFO": "853.3 Kcal",
"NTR_INFO": "탄수화물(g) : 113.1<br/>단백질(g) : 33.8<br/>지방(g) : 22.7<br/>비타민A(R.E) : 392.8<br/>티아민(mg) : 0.7<br/>리보플라빈(mg) : 0.7<br/>비타민C(mg) : 49.0<br/>칼슘(mg) : 449.2<br/>철분(mg) : 3.4",
"MLSV_FROM_YMD": "20190128",
"MLSV_TO_YMD": "20190128"
},
]
}
]
Debugging을 통해 가져온 일부 데이터
위에서 Json 데이터가 어떻게 오고 이루어져 있는지 파악해 보았으니 이제부터 본격적으로 모델을 만들어 보겠습니다. 먼저 가장 큰 틀인 mealServiceDietInfo 부터 만들어 볼게요. 말이 모델이지 클래스 파일을 만든다고 생각하시면 됩니다.
현재 프로젝트를 우클릭하고 Add를 통해 New Item에 들어가 주세요. 저는 MealInfo.cs로 지었습니다. 그리고 그 안의 두 번째로 큰 틀인 head와 row에 대한 클래스 파일도 만들어 주겠습니다. 각각 Head.cs, Row.cs로 지었습니다.
Head안에는 RESULT에 대한 클래스를 하나 더 만들어 주어야 합니다. 왜냐하면 RESULT가 다른 프로퍼티들을 가지고 있기 때문입니다. 그래서 Result.cs 클래스 파일을 하나 더 만들어 주었습니다.
그러면 제일 먼저 Result 모델에 대해서 작성을 해보도록 하겠습니다. Result 클래스로 이동하셔서 아래와 같이 따라 쳐주시면 됩니다. 따라치시기 전에 NugetPackage - Newtonsoft.Json을 다운로드하여주세요.
1
2
3
4
5
6
7
8
9
10
11
12
|
namespace Meal.Model
{
public class Result
{
[JsonProperty("CODE")]
public string code { get; set; }
[JsonProperty("MESSAGE")]
public string message { get; set; }
}
}
|
cs |
Result 모델은 CODE 속성과, MESSAGE 속성을 가지고 있기 때문에 위와 같이 작성해 줍니다. 그리고 [JsonProperty("")]라는 게 보이실 텐데 이것은 서버에서 가져오는 값 즉 URL을 통해 들어오는 Json 파일의 이름을 맞추어 주기 위한 것입니다. 이렇게 해주면 변수에 대해서는 아무렇게 작성해도 값이 제대로 들어오게 됩니다. 다음은 다른 속성과 Result 모델을 가지고 있는 클래스 파일인 Head에 대해서 작성해 볼게요.
1
2
3
4
5
6
7
8
9
10
11
12
|
namespace Meal.Model
{
public class Head
{
[JsonProperty("list_total_count")]
public int ListTotalCount { get; set; }
[JsonProperty("RESULT")]
public Result Result { get; set; }
}
}
|
cs |
위의 내용은 Head 모델에 대한 내용입니다. 현재 이 코드는 약간의 수정이 필요합니다. 그 이유는 밑에서 알려드리도록 하겠습니다. 그다음은 Row 클래스에 대하여 작성해 보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
namespace Meal.Model
{
class Row
{
[JsonProperty("ATPT_OFCDC_SC_CODE")]
public string ATPT_OFCDC_SC_CODE { get; set; }
[JsonProperty("ATPT_OFCDC_SC_NM")]
public string ATPT_OFCDC_SC_NM { get; set; }
[JsonProperty("SD_SCHUL_CODE")]
public string SD_SCHUL_CODE { get; set; }
[JsonProperty("SCHUL_NM")]
public string SCHUL_NM { get; set; }
[JsonProperty("MMEAL_SC_CODE")]
public string MMEAL_SC_CODE { get; set; }
[JsonProperty("MMEAL_SC_NM")]
public string MMEAL_SC_NM { get; set; }
[JsonProperty("MLSV_YMD")]
public string MLSV_YMD { get; set; }
[JsonProperty("MLSV_FGR")]
public string MLSV_FGR { get; set; }
[JsonProperty("DDISH_NM")]
public string DDISH_NM { get; set; }
[JsonProperty("ORPLC_INFO")]
public string ORPLC_INFO { get; set; }
[JsonProperty("CAL_INFO")]
public string CAL_INFO { get; set; }
[JsonProperty("NTR_INFO")]
public string NTR_INFO { get; set; }
[JsonProperty("MLSV_FROM_YMD")]
public string MLSV_FROM_YMD { get; set; }
[JsonProperty("MLSV_TO_YMD")]
public string MLSV_TO_YMD { get; set; }
}
|
cs |
Row 클래스는 속성들이 조금 많습니다. 많더라도 꼭 다 적어주셔야 역직렬화 할 때 문제가 생기지 않습니다. 다음은 Head 모델과 Row 모델을 가지고 있는 MealServiceDietInfo 모델에 대해서 작성해 볼게요.
1
2
3
4
5
6
7
8
9
10
11
12
|
namespace Meal
{
class MealServiceDietInfo
{
[JsonProperty("head")]
List<Head> head { get; set; }
[JsonProperty("row")]
List<Row> row { get; set; }
}
}
|
cs |
MealServiceDietInfo 모델은 Head와 Row를 가지고 있는 클래스 파일입니다. 위에서 분석을 했을 때 Head와 Row를 배열로 가지고 있기 때문에 List <>를 통해 감싸주어야 합니다. 그러면 마지막으로 MealServiceDietInfo를 가지고 있는 MealInfo 클래스에 대해서 작성해 볼게요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
namespace Meal.Model
{
class MealInfo : BindableBase
{
private List<MealServiceDietInfo> mealServiceDietInfos;
[JsonProperty("mealServiceDietInfo")]
public List<MealServiceDietInfo> MealServiceDietInfos
{
get => mealServiceDietInfos;
set
{
SetProperty(ref mealServiceDietInfos, value);
}
}
}
}
|
cs |
MealInfo 클래스 또한 MealServiceDietInfo를 배열로 가지고 있기 때문에 List<>를 통해 감싸줍니다. 이제 Json 데이터를 담을 모든 모델에 대한 작성을 끝내었으니 역직렬화를 하러 가보겠습니다.
1편의 코드에서 작성한 코드를 이어서 작성해 보겠습니다. Web Client와 Web Request 중 아무거나 사용하셔도 괜찮습니다. 저는 WebClient에 이어서 작성해 볼게요
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public string mealWebClient()
{
string mealData = string.Empty;
try
{
WebClient webClient = new WebClient();
webClient.Headers["Content-Type"] = "application/json";
webClient.Encoding = Encoding.UTF8;
using (Stream data = webClient.OpenRead(API_URL))
{
using (StreamReader reader = new StreamReader(data))
{
string json = reader.ReadToEnd();
mealData = json;
JsonToObejct(json); }
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
return mealData;
}
|
cs |
지난 1편에서 작성했었던 mealWebCleint() 메서드입니다. 여기서 result = mealData 밑에 JsonToObject(json); 코드를 작성해 주시고 JsonToObject() 메서드에 대해 작성해 볼게요
1
2
3
4
5
6
7
|
static void JsonToObject(string jsonStr)
{
JObject jObject = JObject.Parse(jsonStr);
MealInfo mealInfo = JsonConvert.DeserializeObject<MealInfo>(jObject.ToString());
Debug.WriteLine(mealInfo); }
|
cs |
매개변수로 json 데이터를 전달받습니다. 그리고 JObject 객체를 생성하고 Pasre를 통해 정리를 해주었습니다. 그리고 좀 전에 제작한 모델인 MealInfo 인스턴스를 생성하고 JsonConvert.DeserializeObject 메서드를 사용합니다. 타입은 인스턴스와 똑같이 MealInfo를 넣고 json 데이터를 가지고 있는 jObject.ToString() 해줍니다. 그리고 실행해 보겠습니다. 결과가 어떻게 될까요?
이대로 실행을 해보니 여러 줄의 오류가 발생했습니다. 왜 그럴까요? 저는 이것을 알아내기 위해 몇 시간 동안 삽질을 했습니다.. 그 이유를 알아보니 제일 상단에서 조금 아래에 Path 'mealServiceDietInfo [0]. head [1]. RESULT.CODE'라는 오류 메시지를 발견할 수 있습니다. 그래서 디버깅을 통해 json 데이터와 실제 데이터를 비교해 보았습니다.
아래를 보면 head의 list_total_count가 3인 것을 볼 수 있습니다. 그런데 실제 데이터를 보게 되면 값이 동일하지 않음을 볼 수 있습니다. 그래서 저는 이 문제를 해결하기 위해 Json 데이터에 대한 모델 변환을 도와주는
를 이용하게 되었습니다. 여기서 변환해주는 결과는 아래와 같은 코드로 변환해 주었습니다.
1
2
3
4
5
6
7
8
9
10
11
|
namespace Meal.Model
{
public class Head
{
[JsonProperty("list_total_count", NullValueHandling = NullValueHandling.Ignore)]
public long? ListTotalCount { get; set; }
[JsonProperty("RESULT", NullValueHandling = NullValueHandling.Ignore)]
public Result Result { get; set; }
}
}
|
cs |
여기서 변환해준 코드를 보면 JsonProperty에 NullValueHandling = NullValueHandling.Ignore를 해주었고 ListTotalCount에? 연산자를 통해 Null 값을 허용해 주었습니다. 왜 이렇게 바꾼 것일까요? 올바르게 변한 코드를 가지고 다시 디버깅을 해보겠습니다.
위를 보시며 알 수 있듯이 성공적으로 역직렬 화가 되었습니다. 그리고 그 안의 내용을 보겠습니다. 아래의 내용을 보면 head [0]에는 ListTotalCount에 대한 값은 들어있지만 Result에 대한 값은 null입니다.
head [1]의 값을 보면 ListTotalCount의 값은 null이지만 Result에는 값이 잘 들어가 있는 것을 볼 수 있습니다. 제가 이 부분에 대해서 빠르게 파악하지 못해 시간을 많이 소모했던 것 같습니다.
그리고 급식 정보가 담겨있는 Row에 대한 정보도 보도록 하겠습니다. 아래를 보면 모델을 작성할 때 썼던 프로퍼티에 대한 값들이 성공적으로 들어가 있는 것을 볼 수 있습니다.
이번 포스팅에서는 URL을 통해 받아온 Json 데이터에 대한 모델을 만들고 역직렬화(객체화)해서 값을 담아 보았습니다. 다음 포스팅인 3편에서는 WPF를 이용해서 간단하게 UI에 급식 정보를 나타내 보는 시간을 가지도록 하겠습니다. 감사합니다. 🌟
'Development > Toy Projects' 카테고리의 다른 글
[프로젝트] 파일 입출력(FILE I/O)을 이용한 Simple Diary 만들기 📖 (0) | 2020.08.15 |
---|---|
[프로젝트] 심심이(SimSimi) API를 이용한 채팅 프로그램 만들기 😀🧨 (하편) (0) | 2020.06.08 |
[프로젝트] 심심이(SimSimi) API를 이용한 채팅 프로그램 만들기 😀🧨 (상편) (3) | 2020.06.07 |
[프로젝트] 급식 데이터를 이용해 간단한 윈도우 응용 프로그램 만들어보기🔥 #3 (0) | 2020.05.14 |
[프로젝트] WebClient와 WebRequest로 NEIS 급식정보 얻어오기🔥 #1 (0) | 2020.05.11 |
댓글