Chuyển đổi dữ liệu XML sang JSON trong C#

Chuyển đổi dữ liệu XML sang JSON trong C#

JSON là một định dạng dùng để truyền dữ liệu giữa các server hoặc giữa client-server rất tốt vì nó giảm thiểu dung lượng dữ liệu thừa (dạng meta) so với XML. XML thì lại được hỗ trợ từ lâu nên có nhiều thư viện để xử lý, nhiều hệ thống hỗ trợ. Sau đây mình trình bày các bước đơn giản để chuyển đổi dữ liệu từ XML sang JSON tương đối gọn nhẹ (light-weight):

Các luật chuyển đổi:

  • Các giá trị chuyển đổi không có kiểu number và boolean
  • XmlDocument luôn được convert thành một object, không bao giờ thành giá trị đơn kể cả khi văn bản XML chỉ chứa một thẻ rỗng (như là <root/>)
  • Các phần tử không chứa attribute, không chứa các phần tử con, chỉ chứa chữ sẽ được chuyển đổi thành dạng: “tagname”: “text”
    XML JSON
    <xx>yyy</xx> { “xx”:”yyy” }
  • Các attribute được chuyển đổi thành dạng: “attribute_name”: “attribute_value”
    XML JSON
    <xx yy=’nn’></xx> { “xx”: {“yy”:”nn”} }
    <xx yy=”></xx> { “xx”: {“yy”:”"} }
  • Phần tử không có phần tử con, không có attribute, không có text sẽ được chuyển đổi thành giá trị null:
    XML JSON
    <xx/> { “xx”:null }
  • Các phần tử chứa cả attribute, text hoặc các phần tử con sẽ được chuyển đổi thành dạng “tagname”: object hoặc một mảng có dạng như sau:
    XML JSON
    <xx yy=’nn’><mm>zzz</mm></xx> { “xx”: {“yy”:”nn”, “mm”:”zzz”} }
    <xx yy=’nn’><mm>zzz</mm><mm>aaa</mm></xx> { “xx”: {“yy”:”nn”, “mm”: [ "zzz", "aaa" ] } }
    <xx><mm>zzz</mm>some text</xx> { “xx”: {“mm”:”zzz”, “value”:”some text”} }
    <xx value=’yyy’>some text<mm>zzz</mm>more text</xx> { “xx”: {“mm”:”zzz”, “value”: [ "yyy", "some text", "more text" ] } }
  • Các ký tự đặc biệt sẽ được che bởi \
    XML JSON
    <aa>/z’z”z\yyy<aa>< {“aa”: “\/z\u0027z\”z\\yyy” }

Ví dụ chuyển đổi:

XML:

<space name="Cake Collage">
<frame>
  <photo img="cakecollage1.jpg" />
  <text string="Browse my cake space" />
  <rule type="F" img="cakecollage9.jpg" x="150" y="0" w="300" h="250" />
  <rule type="F" img="cakecollage2.jpg" x="0" y="0" w="150" h="220" />
</frame>
<frame>
  <photo img="cakecollage2.jpg" />
  <rule type="B" img="cakecollage1.jpg" />
  <rule type="L" img="cakecollage3.jpg" />
</frame>
</space>

Thành JSON:

{ "space":
  { "name": "Cake Collage",
    "frame": [ {"photo": { "img": "cakecollage1.jpg" },
                "rule": [ { "type": "F",
                            "img": "cakecollage9.jpg",
                            "x": "150",
                            "y": "0",
                            "w": "300",
                            "h": "250"
                          },
                          { "type": "F",
                            "img": "cakecollage2.jpg",
                            "x": "0",
                            "y": "0",
                            "w": "150",
                            "h": "220"
                          }
                        ],
                "text": { "string": "Browse my cake space" }
               },
               {"photo": { "img": "cakecollage2.jpg" },
                "rule": [ { "type": "B", "img": "cakecollage1.jpg" },
                          { "type": "L",  "img": "cakecollage3.jpg" }
                        ]
               }
             ]
  }
}

Thực hiện cài đặt hàm XmlToJson trong C# như sau:

private static string XmlToJson(XmlDocument xmlDoc)
{
    StringBuilder sbJSON = new StringBuilder();
    sbJSON.Append("{ ");
    XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);
    sbJSON.Append("}");
    return sbJSON.ToString();
}

private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)
{
    var childAdded = false;
    if (showNodeName)
        sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
    sbJSON.Append("{");

    SortedList childNodeNames = new SortedList();

    //  Xử lý các attribute
    if( node.Attributes!=null)
        foreach (XmlAttribute attr in node.Attributes)
            StoreChildNode(childNodeNames,attr.Name,attr.InnerText);

    //  Xử lý các node con
    foreach (XmlNode cnode in node.ChildNodes)
    {
        childAdded = true;
        if (cnode.ChildNodes[0] is XmlCDataSection)
            StoreChildNode(childNodeNames, cnode.Name, cnode.ChildNodes[0].InnerText);
        else if (cnode is XmlText)
            StoreChildNode(childNodeNames, "value", cnode.InnerText);
        else if (cnode is XmlElement)
            StoreChildNode(childNodeNames, cnode.Name, cnode);
    }

    // Xuất các dữ liệu lưu trong sorted list ra JSON
    foreach (string childname in childNodeNames.Keys)
    {
        childAdded = true;
        ArrayList alChild = (ArrayList)childNodeNames[childname];
        if (alChild.Count == 1)
            OutputNode(childname, alChild[0], sbJSON, true);
        else
        {
            sbJSON.Append(" \"" + SafeJSON(childname) + "\": [ ");
            foreach (object Child in alChild)
                OutputNode(childname, Child, sbJSON, false);
            sbJSON.Remove(sbJSON.Length - 2, 2);
            sbJSON.Append(" ], ");
        }
    }
    sbJSON.Remove(sbJSON.Length - 2, 2);
    sbJSON.Append(childAdded ? " }" : " null");
}

//  StoreChildNode: Lưu dữ liệu vào trong sorted list
private static void StoreChildNode(SortedList childNodeNames, string nodeName, object nodeValue)
{
    if (nodeValue is XmlElement)
    {
        // Chuyển đổi   thành "aa":null
        //             xx thành "aa":"xx"
        XmlNode cnode = (XmlNode)nodeValue;
        if( cnode.Attributes.Count == 0)
        {
            XmlNodeList children = cnode.ChildNodes;
            if( children.Count==0)
                nodeValue = null;
            else if (children.Count == 1 && (children[0] is XmlText))
                nodeValue = ((XmlText)(children[0])).InnerText;
        }
    }

    object oValuesAL = childNodeNames[nodeName];
    ArrayList ValuesAL;
    if (oValuesAL == null)
    {
        ValuesAL = new ArrayList();
        childNodeNames[nodeName] = ValuesAL;
    }
    else
        ValuesAL = (ArrayList)oValuesAL;
    ValuesAL.Add(nodeValue);
}

private static void OutputNode(string childname, object alChild, StringBuilder sbJSON, bool showNodeName)
{
    if (alChild == null)
    {
        if (showNodeName)
            sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
        sbJSON.Append("null");
    }
    else if (alChild is string)
    {
        if (showNodeName)
            sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
        string sChild = (string)alChild;
        sChild = sChild.Trim();
        sbJSON.Append("\"" + SafeJSON(sChild) + "\"");
    }
    else
        XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);
    sbJSON.Append(", ");
}

// Xử lý sIn sao cho tạo thành một chuỗi hợp lệ trong định dạng JSON (chuyển đổi các ký tự đặc biệt với \ đằng trước)
private static string SafeJSON(string sIn)
{
    StringBuilder sbOut = new StringBuilder(sIn.Length);
    foreach (char ch in sIn)
    {
        if (Char.IsControl(ch) || ch == '\'')
        {
            int ich = (int)ch;
            sbOut.Append(@"\u" + ich.ToString("x4"));
            continue;
        }
        else if (ch == '\"' || ch == '\\' || ch == '/')
        {
            sbOut.Append('\\');
        }
        sbOut.Append(ch);
    }
    return sbOut.ToString();
}

Sử dụng hàm XmlToJson:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(@"<space name=""Cake Collage"">
<frame>
<photo img=""cakecollage1.jpg"" />
<text string=""Browse my cake space"" />
<rule type=""F"" img=""cakecollage9.jpg"" x=""150"" y=""0"" w=""300"" h=""250"" />
<rule type=""F"" img=""cakecollage2.jpg"" x=""0"" y=""0"" w=""150"" h=""220"" />
</frame>
<frame>
<photo img=""cakecollage2.jpg"" />
<rule type=""B"" img=""cakecollage1.jpg"" />
<rule type=""L"" img=""cakecollage3.jpg"" />
</frame>
</space>");
string json = XmlToJson(xmlDoc);

Khi đó, kết quả nhận được là chuỗi json nhận được lưu trong biến json có giá trị:

{ "space": { "frame": [ {"photo": {"img": "cakecollage1.jpg" },  "rule": [ {"h": "250", "img": "cakecollage9.jpg", "type": "F", "w": "300", "x": "150", "y": "0" }, {"h": "220", "img": "cakecollage2.jpg", "type": "F", "w": "150", "x": "0", "y": "0" } ], "text": {"string": "Browse my cake space" } }, {"photo": {"img": "cakecollage2.jpg" },  "rule": [ {"img": "cakecollage1.jpg", "type": "B" }, {"img": "cakecollage3.jpg", "type": "L" } ] } ], "name": "Cake Collage" }}

Bạn có thể chạy thử đoạn code trên trong DEMO ONLINE: chuyển đổi XML sang JSON

Khi trích dẫn bài viết từ tek.eten.vn, xin vui lòng ghi rõ nguồn. Chúng tôi sẽ rất cảm ơn bạn!