C# 如何将 JSON 转换为 XML 或 XML 到 JSON?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/814001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:12:51  来源:igfitidea点击:

How to convert JSON to XML or XML to JSON?

c#jsonxmljson.net

提问by David.Chu.ca

I started to use Json.NET to convert a string in JSON format to object or viceversa. I am not sure in the Json.NET framework, is it possible to convert a string in JSON to XML format and viceversa?

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

采纳答案by David Brown

Yes. Using the JsonConvert class which contains helper methods for this precise purpose:

是的。使用包含辅助方法的 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);

Documentation here: Converting between JSON and XML with Json.NET

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

回答by StaxMan

I'm not sure there is point in such conversion (yes, many do it, but mostly to force a square peg through round hole) -- there is structural impedance mismatch, and conversion is lossy. So I would recommend against such format-to-format transformations.

我不确定这种转换是否有意义(是的,很多人都这样做,但主要是为了迫使方钉穿过圆孔)——存在结构阻抗不匹配,并且转换是有损的。所以我建议不要进行这种格式到格式的转换。

But if you do it, first convert from json to object, then from object to xml (and vice versa for reverse direction). Doing direct transformation leads to ugly output, loss of information, or possibly both.

但是如果你这样做,首先从json转换为对象,然后从对象到xml(反之亦然)。进行直接转换会导致丑陋的输出、信息丢失,或者两者兼而有之。

回答by David.Chu.ca

Thanks for David Brown's answer. In my case of JSON.Net 3.5, the convert methods are under the JsonConvert static class:

感谢大卫布朗的回答。在我的 JSON.Net 3.5 中,转换方法位于 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);

回答by Jamon Crockom

Try this function. I just wrote it and haven't had much of a chance to test it, but my preliminary tests are promising.

试试这个功能。我刚刚写了它,并没有太多机会测试它,但我的初步测试很有希望。

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;
}

回答by DaFi4

Yes, you cando it (I do) but Be aware of some paradoxes when converting, and handle appropriately. You cannot automatically conform to all interface possibilities, and there is limited built-in support in controlling the conversion- many JSON structures and values cannot automatically be converted both ways. Keep in mind I am using the default settings with Newtonsoft JSON library and MS XML library, so your mileage may vary:

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

XML -> JSON

XML -> JSON

  1. All data becomes string data (for example you will always get "false"not falseor "0"not 0) Obviously JavaScript treats these differently in certain cases.
  2. Children elements can become nested-object {}OR nested-array [ {} {} ...]depending if there is only one or more than one XML child-element. You would consume these two differently in JavaScript, etc. Different examples of XML conforming to the same schema can produce actually different JSON structures this way. You can add the attribute json:Array='true'to your element to workaround this in some (but not necessarily all) cases.
  3. Your XML must be fairlywell-formed, I have noticed it doesn't need to perfectly conform to W3C standard, but 1. you must have a root element and 2. you cannot start element names with numbers are two of the enforced XML standards I have found when using Newtonsoft and MS libraries.
  4. In older versions, Blank elements do not convert to JSON. They are ignored. A blank element does not become "element":null
  1. 所有数据都变成字符串数据(例如,您总是会得到"false"not false"0"not 0)显然,JavaScript 在某些情况下会以不同的方式处理这些数据。
  2. 子元素可以成为嵌套对象{}或嵌套数组,[ {} {} ...]这取决于是否只有一个或多个 XML 子元素。您将在 JavaScript 等中以不同的方式使用这两个。符合相同模式的不同 XML 示例实际上可以通过这种方式生成不同的 JSON 结构。您可以在元素中添加属性json:Array='true'以在某些(但不一定是所有)情况下解决此问题。
  3. 一定是你的XML相当良好的,我已经注意到它并不需要完全符合W3C标准,但1.你必须有一个根元素2.您无法启动元素名称与数字是两个执行XML标准我在使用 Newtonsoft 和 MS 库时发现。
  4. 在旧版本中,空白元素不会转换为 JSON。它们被忽略。空白元素不会成为“元素”:null

A new update changes this (Thanks to Jon Story for pointing it out): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

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

JSON -> XML

JSON -> XML

  1. You need a top level object that will convert to a root XML element or the parser will fail.
  2. Your object names cannot start with a number, as they cannot be converted to elements (XML is technically even more strict than this) but I can 'get away' with breaking some of the other element naming rules.
  1. 您需要一个将转换为根 XML 元素的顶级对象,否则解析器将失败。
  2. 您的对象名称不能以数字开头,因为它们不能转换为元素(从技术上讲,XML 比这更严格),但我可以“逃脱”破坏其他一些元素命名规则。

Please feel free to mention any other issues you have noticed, I have developed my own custom routines for preparing and cleaning the strings as I convert back and forth. Your situation may or may not call for prep/cleanup. As StaxMan mentions, your situation may actually require that you convert between objects...this could entail appropriate interfaces and a bunch of case statements/etc to handle the caveats I mention above.

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

回答by yourbuddypal

I searched for a long time to find alternative code to the accepted solution in the hopes of not using an external assembly/project. I came up with the following thanks to the source code of the DynamicJsonproject:

我搜索了很长时间来寻找已接受解决方案的替代代码,希望不使用外部程序集/项目。感谢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;
}

Note: I wanted an XmlDocument rather than an XElement for xPath purposes. Also, this code obviously only goes from JSON to XML, there are various ways to do the opposite.

注意:我想要一个 XmlDocument 而不是 XElement 用于 xPath 目的。此外,这段代码显然只能从 JSON 转为 XML,有多种方法可以做相反的事情。

回答by kronenthaler

Here is a simple snippet that converts a XmlNode (recursively) into a hashtable, and groups multiple instances of the same child into an array (as an ArrayList). The Hashtable is usually accepted to convert into JSON by most of the JSON libraries.

这是一个简单的片段,它将 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;
}

回答by Termininja

You can do these conversions also with the .NET Framework:

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

JSON to XML:by using System.Runtime.Serialization.Json

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

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

XML to JSON:by using System.Web.Script.Serialization

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 } };
}

回答by Nimesh khatri

Here is the full c# code to convert xml to json

这是将 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();
 }
}

To convert a given XML string to JSON, simply call XmlToJSON() function as below.

要将给定的 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" }}

回答by Ogglas

I did like David Brown said but I got the following exception.

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

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

One solution would be to modify the XML file with a root element but that is not always necessary and for an XML stream it might not be possible either. My solution below:

一种解决方案是使用根元素修改 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);
            }
        }
    }
}

Example XML that generates the error:

生成错误的示例 XML:

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