一、JSON字符串的成串规则

1)JSON规则中有6中值类型Object、Array、String、Integer、Boolean、Float

2)值类型Object中可以放置任意个键值对,用大括号包住,值可以是中6中类型中的任何一种

3)值类型Array中可以放置任意个值,用方括号包住,值可以是中6中类型中的任何一种

4)值类型String、Integer、Boolean、Float

5)一个完整的有效JSON字符串,是一个Object值或一个Array值

判断一个字符串是否为有效的JSON字符串可以在BEJSON网(http://www.bejson.com/)上进行校验。

二、代码设计思路

因为一个有效的JSON字符串,是一个Object值或一个Array值,而这两个值中,又可以嵌套进JSON中所有的六种值类型,因此对这两种值需要特别加以讨论。

实现将JSON转换为XML格式的函数,被放置在类JSON2XML中的静态方法WriteJsonToXml中

public static void WriteJsonToXml(string path, string json)

path为XML保存到的文件路径,json为被转换的JSON字符串。

该方法的实现思路为:

1)判断path指向的文件是否存在,如果存在,则删除原文件

2)通过XmlTextWriter建立XML文档,编码方案使用GBK

3)设置生成的XML文档绑定json2xml.dtd进行校验

4)判断JSON字符串是Object类型还是Array类型,分类讨论,若为Object则调用AnalyseJsonObject函数解析,若为Array则调用AnalyseJsonArray函数解析。

函数AnalyseJsonObject和函数AnalyseJsonArray分别用来解析Object值和Array值

public static void AnalyseJsonObject(XmlTextWriter writer, JToken jt)
public static void AnalyseJsonArray(XmlTextWriter writer, JToken jt)

解析到嵌套的Object和Array值时,会继续递归调用这两个函数进一步解析

三、JSON2XML代码

class JSON2XML
{
    /// <summary>
    /// 将JSON格式的内容写入到地址为address的XML中
    /// </summary>
    /// <param name="path">要存入的文件地址</param>
    /// <param name="json">源JSON字符串</param>
    public static void WriteJsonToXml(string path, string json)
    {
        //如果存在同名文件先删除
        if (File.Exists(path))
        {
            File.Delete(path);
        }

        //建立XML文档

        XmlTextWriter writer =
            new XmlTextWriter(path, System.Text.Encoding.GetEncoding("GBK"));
        writer.Formatting = System.Xml.Formatting.Indented;

        writer.WriteStartDocument();
        writer.WriteDocType(
            "JSON2XML", "-//Tsybius//JSON2XML//EN", "json2xml.dtd", null);
        writer.WriteComment("这个XML文档中存储了一个JSON格式的信息");

        writer.WriteStartElement("JSON2XML");

        //递归遍历JSON中的项并写入到XML中
        JToken jp = JToken.Parse(json);
        if (jp.Type == JTokenType.Object) //JSON为一个Object的情况
        {
            AnalyseJsonObject(writer, jp);
        }
        else if (jp.Type == JTokenType.Array) //JSON为一个Array的情况
        {
            AnalyseJsonArray(writer, jp);
        }


        writer.WriteEndElement();
        writer.WriteEndDocument();
        writer.Close();

        //XML文档创建结束
    }

    /// <summary>
    /// 将一段JSON格式字符串写入到XML文件中
    /// </summary>
    /// <param name="writer">XML编写器</param>
    /// <param name="json">JSON字符串</param>
    public static void AnalyseJsonObject(XmlTextWriter writer, JToken jt)
    {
        writer.WriteStartElement("JsonObject", "");

        //遍历读取到的JSON字符串
        foreach (JProperty jtemp in jt.Children())
        {
            //根据读入的不同数据类型分类讨论
            switch (jtemp.Value.Type)
            {
                case JTokenType.Object:
                    {
                        writer.WriteStartElement("JsonObject", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        AnalyseJsonObject(writer, jtemp.Value);
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Array:
                    {
                        writer.WriteStartElement("JsonArray", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        AnalyseJsonArray(writer, jtemp.Value);
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.String:
                    {
                        writer.WriteStartElement("JsonString", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        writer.WriteAttributeString("Value", jtemp.Value.ToString());
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Boolean:
                    {
                        writer.WriteStartElement("JsonBoolean", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        writer.WriteAttributeString("Value", jtemp.Value.ToString());
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Integer:
                    {
                        writer.WriteStartElement("JsonInteger", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        writer.WriteAttributeString("Value", jtemp.Value.ToString());
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Float:
                    {
                        writer.WriteStartElement("JsonFloat", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        writer.WriteAttributeString("Value", jtemp.Value.ToString());
                        writer.WriteEndElement();
                    }
                    break;
                default:
                    {
                        writer.WriteStartElement("Default", "");
                        writer.WriteAttributeString("Name", jtemp.Name.ToString());
                        writer.WriteAttributeString("Value", jtemp.Value.ToString());
                        writer.WriteEndElement();
                    }
                    break;
            }
        }

        writer.WriteEndElement();
    }

    /// <summary>
    /// 将一段JSON格式Array内容写入到XML文件中
    /// </summary>
    /// <param name="writer">XML编写器</param>
    /// <param name="json">JSON字符串</param>
    public static void AnalyseJsonArray(XmlTextWriter writer, JToken jt)
    {
        writer.WriteStartElement("JsonArray", "");

        for (int i = 0; i < jt.Count(); i++)
        {
            switch (jt[i].Type)
            {
                case JTokenType.Object:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "Object");
                        AnalyseJsonObject(writer, jt[i]);
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Array:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "Array");
                        JProperty jptemp = new JProperty("ArrayItem", jt[i]);
                        AnalyseJsonArray(writer, jt[i]);
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.String:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "String");
                        writer.WriteAttributeString("Value", jt[i].ToString());
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Boolean:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "Boolean");
                        writer.WriteAttributeString("Value", jt[i].ToString());
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Integer:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "Integer");
                        writer.WriteAttributeString("Value", jt[i].ToString());
                        writer.WriteEndElement();
                    }
                    break;
                case JTokenType.Float:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "Float");
                        writer.WriteAttributeString("Value", jt[i].ToString());
                        writer.WriteEndElement();
                    }
                    break;
                default:
                    {
                        writer.WriteStartElement("ArrayItem", "");
                        writer.WriteAttributeString("Type", "Default");
                        writer.WriteAttributeString("Value", jt[i].ToString());
                        writer.WriteEndElement();
                    }
                    break;
            }
        }

        writer.WriteEndElement();
    }
}

四、调用示例代码

调用函数需要使用一个辅助的工具类FileHelper,这个类中有两个函数

public static string ReadFromFile(string path)
public static void WriteToFile(string path, string content)

ReadFromFile函数从文件中读取内容到字符串

WriteToFile函数将字符串存储到路径为path的文件中

/// <summary>
/// 文件帮助类:读取文件中内容到字符串,将字符串中内容输出到文件
/// </summary>
class FileHelper
{
    public static void WriteToFile(string path, string content)
    {
        //需要 using System.IO
        StreamWriter sw = new StreamWriter(path, false, System.Text.Encoding.UTF8);
        sw.Write(content);
        sw.Close();
        sw.Dispose();
    }

    public static string ReadFromFile(string path)
    {
        //需要 using System.IO
        StreamReader sr = File.OpenText(path);
        return sr.ReadToEnd();
    }
}

Main函数的调用代码如下:

class Program
{
    static void Main(string[] args)
    {
        //写入信息到文件
        FileHelper.WriteToFile("a.txt", "1234");

        //从文件JsonTest.txt中读取信息
        string sJsonText1 = FileHelper.ReadFromFile("JsonTest1.txt");
        string sJsonText2 = FileHelper.ReadFromFile("JsonTest2.txt");

        //将读取的json文本转化后存储到XML中
        JSON2XML.WriteJsonToXml("test1.xml", sJsonText1);
        JSON2XML.WriteJsonToXml("test2.xml", sJsonText2);
    }
}

其中,JsonTest1.txt和JsonTest1.txt是两个存储了两个JSON格式字符串的文件。

五、调用结果

JsonTest1.txt中内容如下:

{
    "Name": "Tsybius",
    "Age": 23,
    "Sex_is_Male": true,
    "Partner": {
        "Partner_Name": "Galatea",
        "Partner_Age": 21,
        "Sex_is_Male": false
    },
    "Achievement": [
        {
            "Achvm1": "Achv1",
            "Prize1": 5000
        },
        {
            "Achvm2": "Achv2",
            "Prize2": 5000
        },
        {
            "Achvm3": "Achv3",
            "Prize3": 5000
        }
    ],
    "OtherParament": [
        "abcd",
        1234,
        true,
        [
            "abcd",
            1234,
            true
        ]
    ]
}

根据Main函数中的代码,转化后到test1.xml中,XML中内容如下:

<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE JSON2XML PUBLIC "-//Tsybius//JSON2XML//EN" "json2xml.dtd">
<!--这个XML文档中存储了一个JSON格式的信息-->
<JSON2XML>
  <JsonObject>
    <JsonString Name="Name" Value="Tsybius" />
    <JsonInteger Name="Age" Value="23" />
    <JsonBoolean Name="Sex_is_Male" Value="True" />
    <JsonObject Name="Partner">
      <JsonObject>
        <JsonString Name="Partner_Name" Value="Galatea" />
        <JsonInteger Name="Partner_Age" Value="21" />
        <JsonBoolean Name="Sex_is_Male" Value="False" />
      </JsonObject>
    </JsonObject>
    <JsonArray Name="Achievement">
      <JsonArray>
        <ArrayItem Type="Object">
          <JsonObject>
            <JsonString Name="Achvm1" Value="Achv1" />
            <JsonInteger Name="Prize1" Value="5000" />
          </JsonObject>
        </ArrayItem>
        <ArrayItem Type="Object">
          <JsonObject>
            <JsonString Name="Achvm2" Value="Achv2" />
            <JsonInteger Name="Prize2" Value="5000" />
          </JsonObject>
        </ArrayItem>
        <ArrayItem Type="Object">
          <JsonObject>
            <JsonString Name="Achvm3" Value="Achv3" />
            <JsonInteger Name="Prize3" Value="5000" />
          </JsonObject>
        </ArrayItem>
      </JsonArray>
    </JsonArray>
    <JsonArray Name="OtherParament">
      <JsonArray>
        <ArrayItem Type="String" Value="abcd" />
        <ArrayItem Type="Integer" Value="1234" />
        <ArrayItem Type="Boolean" Value="True" />
        <ArrayItem Type="Array">
          <JsonArray>
            <ArrayItem Type="String" Value="abcd" />
            <ArrayItem Type="Integer" Value="1234" />
            <ArrayItem Type="Boolean" Value="True" />
          </JsonArray>
        </ArrayItem>
      </JsonArray>
    </JsonArray>
  </JsonObject>
</JSON2XML>

JsonTest2.txt中内容如下:

[
    1,
    2,
    [
        1,
        2,
        3
    ]
]

根据Main函数中的代码,转化后到test2.xml中,XML中内容如下:

<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE JSON2XML PUBLIC "-//Tsybius//JSON2XML//EN" "json2xml.dtd">
<!--这个XML文档中存储了一个JSON格式的信息-->
<JSON2XML>
  <JsonArray>
    <ArrayItem Type="Integer" Value="1" />
    <ArrayItem Type="Integer" Value="2" />
    <ArrayItem Type="Array">
      <JsonArray>
        <ArrayItem Type="Integer" Value="1" />
        <ArrayItem Type="Integer" Value="2" />
        <ArrayItem Type="Integer" Value="3" />
      </JsonArray>
    </ArrayItem>
  </JsonArray>
</JSON2XML>

六、校验XML文件用的DTD文件-json2xml.dtd

json2xml.dtd可以用来校验本程序生成的XML文件

<!--文件List.xml的DTD文档-->
 
<!--List:根节点,根节点包括且仅包括一个JsonObject或JsonArray-->
<!ELEMENT JSON2XML (JsonObject | JsonArray)+>

<!--JsonArray:Json中的Array,包括零个或多个数组元素-->
<!ELEMENT JsonArray (ArrayItem | EMPTY)*>
<!ATTLIST JsonArray Name CDATA #IMPLIED>

<!--ArrayItem:Json中Array的一个元素-->
<!ELEMENT ArrayItem (JsonObject | JsonArray | EMPTY)*>
<!ATTLIST ArrayItem Type CDATA #IMPLIED>
<!ATTLIST ArrayItem Value CDATA #IMPLIED>

<!--JsonObject:Json中的Object,包括多组键值对-->
<!ELEMENT JsonObject (
    JsonObject | JsonArray | JsonString |
    JsonBoolean | JsonInteger | JsonFloat | EMPTY)*>
<!ATTLIST JsonObject Name CDATA #IMPLIED>

<!--JsonString:Json中的String型数据-->
<!ELEMENT JsonString EMPTY>
<!ATTLIST JsonString Name CDATA #IMPLIED>
<!ATTLIST JsonString Value CDATA #IMPLIED>

<!--JsonBoolean:Json中的Boolean型数据-->
<!ELEMENT JsonBoolean EMPTY>
<!ATTLIST JsonBoolean Name CDATA #IMPLIED>
<!ATTLIST JsonBoolean Value CDATA #IMPLIED>

<!--JsonInteger:Json中的Integer型数据-->
<!ELEMENT JsonInteger EMPTY>
<!ATTLIST JsonInteger Name CDATA #IMPLIED>
<!ATTLIST JsonInteger Value CDATA #IMPLIED>

<!--JsonFloat:Json中的Float型数据-->
<!ELEMENT JsonFloat EMPTY>
<!ATTLIST JsonFloat Name CDATA #IMPLIED>
<!ATTLIST JsonFloat Value CDATA #IMPLIED>

<!--文档结束-->