如何将JSON转换为XML或将XML转换为JSON?


282

我开始使用Json.NET将JSON格式的字符串转换为对象,反之亦然。我不确定在Json.NET框架中是否可以将JSON中的字符串转换为XML格式,反之亦然?


请注意,如StaxMan所说,如果有的话。元素节点中的空格,它将被xml忽略。对于前。“学生ID”:属性名称中空间的xml结果bcuz不会为11000。xml不接受在Element Node中使用空格。
丹尼尔·B

Answers:


424

是。使用JsonConvert类包含用于此精确目的的辅助方法:

// To convert an XML node contained in string xml into a JSON string   
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);

// To convert JSON text contained in string json into an XML node
XmlDocument doc = JsonConvert.DeserializeXmlNode(json);

此处的文档:使用Json.NET在JSON和XML之间进行转换


3
我找不到这堂课。我使用NewtonSoft Json.net 3.5。
David.Chu.ca,2009年

3
看来这个功能已经转移到Newtonsoft.Json.Converters.XmlNodeConverter类JSON.NET 3.5:james.newtonking.com/projects/json/help/html/...
大卫·布朗

3
仅供参考,这里有潜在的问题。当我将xml节点数组转换为json时,它正在json中创建数组。但是,当我遍历一个计数为1的xml节点数组时,则json转换不再格式化数组了。具有单个元素的xml数组在此处的翻译中丢失了。
Levitikon 2012年

3
惊喜惊喜-这是XML和JSON之间的阻抗,也是(IMO)在两者之间直接转换不是一个好主意的原因。但是,嘿,有很多开发人员强烈反对(根据我的回答,我不赞成这样做)并且不介意这些意外的数据转换或潜在的数据丢失……
StaxMan 2012年

7
@StaxMan:我想每个人都可以同意,没有标准化的方式来表示JSON格式的XML文档。您的答案可能被否决了,因为它实际上并未回答问题。OP并没有询问他是否应该进行转换,而是询问他是否可以使用已经可以使用的工具进行转换。
大卫·布朗

46

是的,您可以做到(我可以),但是在转换时请注意一些悖论,并进行适当的处​​理。您无法自动符合所有接口的可能性,并且控制转换的内置支持有限-许多JSON结构和值无法自动以两种方式转换。请记住,我在Newtonsoft JSON库和MS XML库中使用默认设置,因此您的里程可能会有所不同:

XML-> JSON

  1. 所有数据都变成字符串数据(例如,您将始终得到“ false”而不是false“ 0”而不是0)显然,JavaScript在某些情况下会以不同的方式对待它们。
  2. 子元素可以成为嵌套对象{}或嵌套数组,[ {} {} ...]这取决于是否只有一个或多个XML子元素。您将在JavaScript等中以不同方式使用这两种方式。遵循同一模式的XML的不同示例可以通过这种方式实际产生不同的JSON结构。您可以在元素中添加json:Array ='true'属性,以在某些(但不一定是全部)情况下解决此问题。
  3. 一定是你的XML 相当良好的,我已经注意到它并不需要完全符合W3C标准,但1.你必须有一个根元素2.您无法启动元素名称与数字是两个执行XML标准我在使用Newtonsoft和MS库时发现了。
  4. 在旧版本中,Blank元素不会转换为JSON。他们被忽略。空白元素不会变为“ element”:null

一个新的更新对此进行了更改(感谢Jon Story指出了这一点):https : //www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

JSON-> XML

  1. 您需要一个顶级对象,该对象将转换为根XML元素,否则解析器将失败。
  2. 您的对象名称不能以数字开头,因为它们不能转换为元素(从技术上说,XML比这更严格),但是我可以打破其他一些元素命名规则来“逃脱”。

请随时提及您注意到的任何其他问题,我开发了自己的自定义例程,用于在来回转换时准备和清理字符串。您的情况可能会也可能不会要求进行准备/清除。正如StaxMan所提到的,您的情况实际上可能需要您在对象之间进行转换...这可能需要适当的接口和一堆case语句/等来处理我在上面提到的警告。


这个!我简短的回答(有时被严重否定)的基础很好地阐述了-如果您盲目直接转换,会有很多很多陷阱。它们可能不会阻止特定用途的问题,但对其他人也可能很讨厌。
StaxMan

1
关于#4 XML - > JSON:您可以使用NullValueHandling属性来指定空值应明确包括- newtonsoft.com/json/help/html/...
乔恩故事

此注释中的问题描述非常适用于将JSON转换为XML或反向的所有算法实现。一旦人们接受到不可能同时实现完美的双向保真度,并且同时以太“当事人”或“受约束”(预定的模式/格式)的输入和输出是不可能的。-在一般情况下。
DALDEI

33

您也可以使用.NET Framework进行以下转换:

JSON到XML:通过使用System.Runtime.Serialization.Json

var xml = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(
    Encoding.ASCII.GetBytes(jsonString), new XmlDictionaryReaderQuotas()));

XML到JSON:通过使用System.Web.Script.Serialization

var json = new JavaScriptSerializer().Serialize(GetXmlData(XElement.Parse(xmlString)));

private static Dictionary<string, object> GetXmlData(XElement xml)
{
    var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
    if (xml.HasElements) attr.Add("_value", xml.Elements().Select(e => GetXmlData(e)));
    else if (!xml.IsEmpty) attr.Add("_value", xml.Value);

    return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
}

我在GetXmlData上收到错误消息“当前上下文中不存在名称'GetXmlData'”我是否缺少using指令?
TimSmith-Aardwolf '16

4
@ TimSmith-Aardwolf,是您需要的所有代码。要使用System.Web.Script.Serialization,需要在“引用”中添加System.Web.Extensions程序集。
Termmininja '16

@ Termininja,JSON到XML的类型也给我,如何删除呢?
饼干

@Termininja,完美,谢谢。
饼干

30

我不确定这种转换是否有意义(是的,很多人都这样做,但主要是迫使方钉穿过圆孔)-结构阻抗不匹配,转换是有损耗的。因此,我建议不要使用这种格式到格式的转换。

但是,如果要这样做,请先从json转换为对象,然后再从object转换为xml(反之亦然)。直接进行转换会导致输出丑陋,信息丢失或可能同时导致两者。


1
即使您的答案被粉碎,我也很高兴它在这里。我想进行转换,正在考虑跳过c#中间对象,但现在还不确定。否则,我将需要基于XSD生成c#对象,并且由于它仅用于转换目的,因此看起来像是浪费的层(和精力)。如果您有示例或更多有关如何有损的详细信息,那将很高兴看到。
CRice 2014年

不知道为什么这被否决了。我目前正在修复与我们产品中的几个XML <-> JSON转换步骤有关的错误。从JSON转换为XML时,多数归因于数字类型的丢失。
rikkit 2014年

硬道理,有用的答案。
FailedUnitTest

@CRice Years为时已晚,但是拥有传输对象可以在某种程度上保留XML模式。例如,如Levitikon所提出的那样,如果您尝试转换具有单个元素数组的XML文档,则JSON转换无法知道它是一个数组,除非它来自具有数组类型的传输对象。
jpaugh

1
Newtonsoft.JSON的XmlNodeConverter具有配置选项,可避免从JSON转换为XML并转换回JSON时出现此问题,但无法捕获原始格式为XML的情况
jpaugh

27

感谢David Brown的回答。以JSON.Net 3.5为例,convert方法在JsonConvert静态类下:

XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(myJsonString); // is node not note
// or .DeserilizeXmlNode(myJsonString, "root"); // if myJsonString does not have a root
string jsonString = JsonConvert.SerializeXmlNode(myXmlNode);

4
如果您的数据是数组,那么您需要执行以下操作:JsonConvert.DeserializeXmlNode(“ {\” Row \“:” + json +“}”,“ root”)。ToXmlString()否则,您将得到一个“ XmlNodeConverter只能转换以对象开头的JSON。” 例外。
米切尔Skurnik

是的,您不能以数字开头。JsonConvert.DeserializeXmlNode(“ {\” 1Row \“:” + json +“}”,“ root”)。ToXmlString()将失败
DaFi4 2016年

上面的答案和@mitchell评论帮助我..谢谢
Ajay2707

8

我搜索了很长时间,以找到可接受的解决方案的替代代码,希望不使用外部程序集/项目。由于DynamicJson项目的源代码,我提出了以下建议:

public XmlDocument JsonToXML(string json)
{
    XmlDocument doc = new XmlDocument();

    using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(json), XmlDictionaryReaderQuotas.Max))
    {
        XElement xml = XElement.Load(reader);
        doc.LoadXml(xml.ToString());
    }

    return doc;
}

注意:出于xPath的目的,我需要XmlDocument而不是XElement。同样,此代码显然仅从JSON到XML,有多种相反的方法。


1
我最近需要在SQLCLR中执行此操作,并且无法获取依赖关系,因此我只是硬着头皮写了这个json-to-xml转换例程,它非常简单,仅约20行代码。
哥迪

如何从XML删除打字机?
饼干

6

这是将xml转换为json的完整c#代码

public static class JSon
{
public static string XmlToJSON(string xml)
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);

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

//  XmlToJSONnode:  Output an XmlElement, possibly as part of a higher array
private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)
{
    if (showNodeName)
        sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
    sbJSON.Append("{");
    // Build a sorted list of key-value pairs
    //  where   key is case-sensitive nodeName
    //          value is an ArrayList of string or XmlElement
    //  so that we know whether the nodeName is an array or not.
    SortedList<string, object> childNodeNames = new SortedList<string, object>();

    //  Add in all node attributes
    if (node.Attributes != null)
        foreach (XmlAttribute attr in node.Attributes)
            StoreChildNode(childNodeNames, attr.Name, attr.InnerText);

    //  Add in all nodes
    foreach (XmlNode cnode in node.ChildNodes)
    {
        if (cnode is XmlText)
            StoreChildNode(childNodeNames, "value", cnode.InnerText);
        else if (cnode is XmlElement)
            StoreChildNode(childNodeNames, cnode.Name, cnode);
    }

    // Now output all stored info
    foreach (string childname in childNodeNames.Keys)
    {
        List<object> alChild = (List<object>)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(" }");
}

//  StoreChildNode: Store data associated with each nodeName
//                  so that we know whether the nodeName is an array or not.
private static void StoreChildNode(SortedList<string, object> childNodeNames, string nodeName, object nodeValue)
{
    // Pre-process contraction of XmlElement-s
    if (nodeValue is XmlElement)
    {
        // Convert  <aa></aa> into "aa":null
        //          <aa>xx</aa> into "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;
        }
    }
    // Add nodeValue to ArrayList associated with each nodeName
    // If nodeName doesn't exist then add it
    List<object> ValuesAL;

    if (childNodeNames.ContainsKey(nodeName))
    {
        ValuesAL = (List<object>)childNodeNames[nodeName];
    }
    else
    {
        ValuesAL = new List<object>();
        childNodeNames[nodeName] = ValuesAL;
    }
    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(", ");
}

// Make a string safe for JSON
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();
 }
}

要将给定的XML字符串转换为JSON,只需调用XmlToJSON()函数,如下所示。

string xml = "<menu id=\"file\" value=\"File\"> " +
              "<popup>" +
                "<menuitem value=\"New\" onclick=\"CreateNewDoc()\" />" +
                "<menuitem value=\"Open\" onclick=\"OpenDoc()\" />" +
                "<menuitem value=\"Close\" onclick=\"CloseDoc()\" />" +
              "</popup>" +
            "</menu>";

string json = JSON.XmlToJSON(xml);
// json = { "menu": {"id": "file", "popup": { "menuitem": [ {"onclick": "CreateNewDoc()", "value": "New" }, {"onclick": "OpenDoc()", "value": "Open" }, {"onclick": "CloseDoc()", "value": "Close" } ] }, "value": "File" }}

3

试试这个功能。我只是编写它而没有太多机会对其进行测试,但是我的初步测试是有希望的。

public static XmlDocument JsonToXml(string json)
{
    XmlNode newNode = null;
    XmlNode appendToNode = null;
    XmlDocument returnXmlDoc = new XmlDocument();
    returnXmlDoc.LoadXml("<Document />");
    XmlNode rootNode = returnXmlDoc.SelectSingleNode("Document");
    appendToNode = rootNode;

    string[] arrElementData;
    string[] arrElements = json.Split('\r');
    foreach (string element in arrElements)
    {
        string processElement = element.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim();
        if ((processElement.IndexOf("}") > -1 || processElement.IndexOf("]") > -1) && appendToNode != rootNode)
        {
            appendToNode = appendToNode.ParentNode;
        }
        else if (processElement.IndexOf("[") > -1)
        {
            processElement = processElement.Replace(":", "").Replace("[", "").Replace("\"", "").Trim();
            newNode = returnXmlDoc.CreateElement(processElement);
            appendToNode.AppendChild(newNode);
            appendToNode = newNode;
        }
        else if (processElement.IndexOf("{") > -1 && processElement.IndexOf(":") > -1)
        {
            processElement = processElement.Replace(":", "").Replace("{", "").Replace("\"", "").Trim();
            newNode = returnXmlDoc.CreateElement(processElement);
            appendToNode.AppendChild(newNode);
            appendToNode = newNode;
        }
        else
        {
            if (processElement.IndexOf(":") > -1)
            {
                arrElementData = processElement.Replace(": \"", ":").Replace("\",", "").Replace("\"", "").Split(':');
                newNode = returnXmlDoc.CreateElement(arrElementData[0]);
                for (int i = 1; i < arrElementData.Length; i++)
                {
                    newNode.InnerText += arrElementData[i];
                }

                appendToNode.AppendChild(newNode);
            }
        }
    }

    return returnXmlDoc;
}

2

这是一个简单的代码段,该代码段将XmlNode(递归)转换为哈希表,并将同一子项的多个实例分组为一个数组(作为ArrayList)。通常,大多数JSON库都接受将Hashtable转换为JSON。

protected object convert(XmlNode root){
    Hashtable obj = new Hashtable();
    for(int i=0,n=root.ChildNodes.Count;i<n;i++){
        object result = null;
        XmlNode current = root.ChildNodes.Item(i);

        if(current.NodeType != XmlNodeType.Text)
            result = convert(current);
        else{
            int resultInt;
            double resultFloat;
            bool resultBoolean;
            if(Int32.TryParse(current.Value, out resultInt)) return resultInt;
            if(Double.TryParse(current.Value, out resultFloat)) return resultFloat;
            if(Boolean.TryParse(current.Value, out resultBoolean)) return resultBoolean;
            return current.Value;
        }

        if(obj[current.Name] == null)
            obj[current.Name] = result;
        else if(obj[current.Name].GetType().Equals(typeof(ArrayList)))
            ((ArrayList)obj[current.Name]).Add(result);
        else{
            ArrayList collision = new ArrayList();
            collision.Add(obj[current.Name]);
            collision.Add(result);
            obj[current.Name] = collision;
        }
    }

    return obj;
}

1

Cinchoo ETL一个开源库,可使用几行代码轻松地将Xml转换为JSON

Xml-> JSON:

using (var p = new ChoXmlReader("sample.xml"))
{
    using (var w = new ChoJSONWriter("sample.json"))
    {
        w.Write(p);
    }
}

JSON-> Xml:

using (var p = new ChoJsonReader("sample.json"))
{
    using (var w = new ChoXmlWriter("sample.xml"))
    {
        w.Write(p);
    }
}

查阅CodeProject文章以获取其他帮助。

免责声明:我是这个图书馆的作者。


0

我的确像大卫·布朗说的那样,但是我得到了以下例外。

$exception {"There are multiple root elements. Line , position ."} System.Xml.XmlException

一种解决方案是用根元素修改XML文件,但这并非总是必须的,对于XML流,也可能不可能。我的解决方案如下:

var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\App_Data"));
var directoryInfo = new DirectoryInfo(path);
var fileInfos = directoryInfo.GetFiles("*.xml");

foreach (var fileInfo in fileInfos)
{
    XmlDocument doc = new XmlDocument();
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;

    using (XmlReader reader = XmlReader.Create(fileInfo.FullName, settings))
    {
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                var node = doc.ReadNode(reader);
                string json = JsonConvert.SerializeXmlNode(node);
            }
        }
    }
}

生成错误的示例XML:

<parent>
    <child>
        Text
    </child>
</parent>
<parent>
    <child>
        <grandchild>
            Text
        </grandchild>
        <grandchild>
            Text
        </grandchild>
    </child>
    <child>
        Text
    </child>
</parent>

1
您的示例XML不是XML文档,因为它没有单个根节点。但是,那可能是一个XML片段。
罗伯特·麦基

0

我使用以下方法将JSON转换为XML

List <Item> items;
public void LoadJsonAndReadToXML() {
  using(StreamReader r = new StreamReader(@ "E:\Json\overiddenhotelranks.json")) {
    string json = r.ReadToEnd();
    items = JsonConvert.DeserializeObject <List<Item>> (json);
    ReadToXML();
  }
}

public void ReadToXML() {
  try {
    var xEle = new XElement("Items",
      from item in items select new XElement("Item",
        new XElement("mhid", item.mhid),
        new XElement("hotelName", item.hotelName),
        new XElement("destination", item.destination),
        new XElement("destinationID", item.destinationID),
        new XElement("rank", item.rank),
        new XElement("toDisplayOnFod", item.toDisplayOnFod),
        new XElement("comment", item.comment),
        new XElement("Destinationcode", item.Destinationcode),
        new XElement("LoadDate", item.LoadDate)
      ));

    xEle.Save("E:\\employees.xml");
    Console.WriteLine("Converted to XML");
  } catch (Exception ex) {
    Console.WriteLine(ex.Message);
  }
  Console.ReadLine();
}

我已经使用名为Item的类来表示元素

public class Item {
  public int mhid { get; set; }
  public string hotelName { get; set; }
  public string destination { get; set; }
  public int destinationID { get; set; }
  public int rank { get; set; }
  public int toDisplayOnFod { get; set; }
  public string comment { get; set; }
  public string Destinationcode { get; set; }
  public string LoadDate { get; set; }
}

有用....


0

对于转换JSON字符串,请XML尝试以下操作:

    public string JsonToXML(string json)
    {
        XDocument xmlDoc = new XDocument(new XDeclaration("1.0", "utf-8", ""));
        XElement root = new XElement("Root");
        root.Name = "Result";

        var dataTable = JsonConvert.DeserializeObject<DataTable>(json);
        root.Add(
                 from row in dataTable.AsEnumerable()
                 select new XElement("Record",
                                     from column in dataTable.Columns.Cast<DataColumn>()
                                     select new XElement(column.ColumnName, row[column])
                                    )
               );


        xmlDoc.Add(root);
        return xmlDoc.ToString();
    }

对于转换XMLJSON试试这个:

    public string XmlToJson(string xml)
    {
       XmlDocument doc = new XmlDocument();
       doc.LoadXml(xml);

       string jsonText = JsonConvert.SerializeXmlNode(doc);
       return jsonText;
     }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.