Json / Xml 문자열을 DataSet 에 넣는 코드
(5년전 작성한 블로그글에서 발췌한것으로 코드가 지저분하고 Json 이나 Xml 문자열에 따라 오류발생 가능)
JObject인경우와 JArray 인 경우는 재귀되도록 구현
(하나의 테이블에 담아야 하는 기능이 필요하여 개발한것으로 여러 JObject 나 JArray 에서 명칭이 같은 것이 있으면 오류)
-> 수정
eachTable 이 true 이면 각 Object 별로 테이블 생성
false 이면 기존과 동일하게 하나의 테이블에 삽입
(맨 윗단의 Object 까지만 각각 테이블 생성하도록 한것으로 내부에 있는 Object 중복은 오류)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Xml.Linq;
using System.IO;
namespace JsonToDataSet
{
public partial class Form1 : Form
{
private bool m_eachTable = false;
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
textBox2.Text = "";
this.PrintRows(JsonToDataSet(textBox1.Text, m_eachTable));
}
private void button2_Click(object sender, EventArgs e)
{
textBox2.Text = "";
XElement xEle = XElement.Parse(textBox1.Text);
DataSet ds = new DataSet();
ds.ReadXml(new StringReader(new XElement("a", xEle).ToString()));
this.PrintRows(ds);
}
private void PrintRows(DataSet dataSet)
{
foreach (DataTable table in dataSet.Tables)
{
textBox2.Text += table.TableName + "\r\n";
foreach (DataRow row in table.Rows)
{
foreach (DataColumn column in table.Columns)
{
textBox2.Text += column.ColumnName + " : " + row[column].ToString() + "\r\n";
}
textBox2.Text += "\r\n";
}
textBox2.Text += "\r\n";
}
}
public DataSet JsonToDataSet(string jsonString)
{
return JsonToDataSet(jsonString, false);
}
public DataSet JsonToDataSet(string jsonString, bool eachTable)
{
DataSet ds = new DataSet("ROOT");
DataTable dt = new DataTable();
JArray trgArray = null;
jsonString = "{\"row\":" + jsonString + "}";
var jsonLinq = JObject.Parse(jsonString);
if (jsonLinq.Descendants().First() != null)
{
try
{
JToken srcArrayStatus = jsonLinq.Descendants().First();
trgArray = new JArray();
foreach (JObject row in srcArrayStatus.Children<JObject>())
{
var cleanRow = new JObject();
foreach (JProperty column in row.Properties())
{
JsonConvert.SerializeObject(ds, Formatting.Indented);
cleanRow = JTokenIntoDataSet(column, cleanRow);
if (eachTable && cleanRow.Count != 0) //각 Obejct 별로 Table 생성
{
trgArray.Add(cleanRow);
DataTable dt2 = new DataTable();
dt2 = JsonConvert.DeserializeObject<DataTable>(trgArray.ToString());
dt2.TableName = column.Name;
ds.Tables.Add(dt2);
cleanRow.RemoveAll();
trgArray.RemoveAll();
}
}
trgArray.Add(cleanRow);
}
if (!eachTable && trgArray.Count != 0)
{
dt = JsonConvert.DeserializeObject<DataTable>(trgArray.ToString());
dt.TableName = "DataBlock1";
ds.Tables.Add(dt);
}
}
catch (Exception ex)
{ }
}
return ds;
}
public JObject JTokenIntoDataSet(JToken jToken, JObject cleanRow)
{
if ((jToken as JProperty).Value != null) // "name" : "value"
{
if ((jToken as JProperty).Value is JValue)
{
cleanRow.Add((jToken as JProperty).Name, (jToken as JProperty).Value);
}
else if ((jToken as JProperty).Value is JObject) // "name" : { "name" : "value", ... }
{
foreach (JToken row in (jToken as JProperty).Value.Children<JToken>())
{
cleanRow = JTokenIntoDataSet(row, cleanRow);
}
}
else if ((jToken as JProperty).Value is JArray)
{
JToken srcArrayData = ((jToken as JProperty).Value as JArray).Descendants().First();
while (srcArrayData.Next == null)
{
foreach (JToken row in srcArrayData.Children<JToken>())
{
JToken jtk = row;
cleanRow = JTokenIntoDataSet(jtk, cleanRow);
}
srcArrayData = srcArrayData.Next;
}
}
}
return cleanRow;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void label2_Click(object sender, EventArgs e)
{
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if(m_eachTable)
{
m_eachTable = false;
}
else
{
m_eachTable = true;
}
}
}
}
--
리팩토링
using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Xml.Linq;
namespace JsonToDataSet
{
public partial class Form1 : Form
{
private bool m_eachTable = false;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox2.Clear();
var ds = JsonToDataSet(textBox1.Text, m_eachTable);
PrintRows(ds);
}
private void button2_Click(object sender, EventArgs e)
{
textBox2.Clear();
XElement xEle = XElement.Parse(textBox1.Text);
DataSet ds = new DataSet();
ds.ReadXml(new StringReader(new XElement("Root", xEle).ToString()));
PrintRows(ds);
}
private void PrintRows(DataSet dataSet)
{
foreach (DataTable table in dataSet.Tables)
{
textBox2.AppendText(table.TableName + Environment.NewLine);
foreach (DataRow row in table.Rows)
{
foreach (DataColumn column in table.Columns)
{
textBox2.AppendText($"{column.ColumnName} : {row[column]}{Environment.NewLine}");
}
textBox2.AppendText(Environment.NewLine);
}
textBox2.AppendText(Environment.NewLine);
}
}
public DataSet JsonToDataSet(string jsonString, bool eachTable = false)
{
var ds = new DataSet("ROOT");
try
{
// JSON 루트 보정
var wrappedJson = "{ \"row\": " + jsonString + " }";
var root = JObject.Parse(wrappedJson);
var rows = root["row"] as JArray ?? new JArray(root["row"]);
var table = new DataTable("DataBlock1");
foreach (var row in rows.Children<JObject>())
{
var cleanRow = ExtractFields(row);
if (eachTable && cleanRow.Count > 0)
{
var dt = JsonConvert.DeserializeObject<DataTable>(new JArray(cleanRow).ToString());
dt.TableName = row.Path.Split('.').LastOrDefault() ?? "Table";
ds.Tables.Add(dt);
}
else
{
table = EnsureTableSchema(table, cleanRow);
var newRow = table.NewRow();
foreach (var col in cleanRow.Properties())
{
newRow[col.Name] = col.Value.ToString();
}
table.Rows.Add(newRow);
}
}
if (!eachTable && table.Rows.Count > 0)
{
ds.Tables.Add(table);
}
}
catch (Exception ex)
{
MessageBox.Show("JSON 변환 실패: " + ex.Message);
}
return ds;
}
/// <summary>
/// JSON 객체 → Key-Value 평탄화
/// </summary>
private JObject ExtractFields(JToken token, JObject result = null, string prefix = "")
{
result ??= new JObject();
if (token is JObject obj)
{
foreach (var prop in obj.Properties())
{
ExtractFields(prop.Value, result, prefix + prop.Name + "_");
}
}
else if (token is JArray arr)
{
int idx = 0;
foreach (var item in arr)
{
ExtractFields(item, result, prefix + idx + "_");
idx++;
}
}
else if (token is JValue val)
{
result[prefix.TrimEnd('_')] = val.ToString();
}
return result;
}
/// <summary>
/// DataTable 스키마 자동 확장
/// </summary>
private DataTable EnsureTableSchema(DataTable table, JObject row)
{
foreach (var prop in row.Properties())
{
if (!table.Columns.Contains(prop.Name))
{
table.Columns.Add(prop.Name, typeof(string));
}
}
return table;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
m_eachTable = checkBox1.Checked;
}
}
}
'C# .Net' 카테고리의 다른 글
| TCP/IP 통신 Server 및 Client 예제 in C# (Winform) (0) | 2022.09.20 |
|---|---|
| RESTful API Server 구현 예제 in C# (0) | 2022.09.19 |
| A, B, C, D, ... Z, AA, AB, AC, ... AZ, BA, BB, ... ZZ, AAA, AAB... 등 알파벳 이름 자동 생성 in C# (Excel 방식) 예제 (0) | 2022.09.14 |
| .Net C/C++/C# Stack Size 변경 방법 (0) | 2021.11.17 |