如何将JSON转换为XML或XML到JSON?
我开始使用Json.NET将JSON格式的字符串转换为对象或反之亦然。 我不确定在Json.NET框架中,是否可以将JSON中的字符串转换为XML格式,反之亦然?
是。 使用包含辅助方法的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
是的,你可以做(我做),但转换时要注意一些悖论,并适当地处理。 您不能自动遵守所有接口的可能性,并且控制转换的内置支持有限 – 许多JSON结构和值不能自动转换。 请记住,我正在使用Newtonsoft JSON库和MS XML库的默认设置,因此您的里程可能会有所不同:
XML – > JSON
- 所有的数据成为字符串数据(例如,你总是会得到“假”不是假或“0”不0 )显然JavaScript在某些情况下对待这些不同。
- 子元素可以成为嵌套对象
[]
或嵌套数组,取决于是否只有一个或多个XML子元素。 您将在JavaScript等中使用这两种不同的方法。符合相同模式的XML的不同示例可以以这种方式生成实际上不同的JSON结构。 你可以添加属性json:Array ='true'到你的元素来解决一些(但不一定是全部)的情况。 - 你的XML必须是相当良好的形式,我注意到它不需要完全符合W3C标准,但是1.你必须有一个根元素,2.你不能启动元素名称,数字是两个强制的XML标准我发现使用Newtonsoft和MS库时。
- 空白元素不会转换为JSON。 他们被忽略。 一个空白元素不会变成“元素”:null
JSON – > XML
- 您需要一个将转换为根XML元素的顶级对象,否则解析器将失败。
- 你的对象名称不能以数字开头,因为它们不能被转换为元素(XML在技术上比这更严格),但是我可以打破一些其他的元素命名规则。
请随意提及您已经注意到的任何其他问题,我已经开发了我自己的定制例程,用于准备和清理字符串,当我来回转换时。 你的情况可能会或可能不需要准备/清理。 正如StaxMan提到的,你的情况可能实际上需要你在对象之间进行转换…这可能需要适当的接口和一些case语句来处理上面提到的警告。
感谢大卫布朗的答案。 在我的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);
您也可以使用.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 } }; }
我不确定这样的转换是否有意义(是的,很多人这样做,但主要是通过圆孔迫使一个方形钉) – 结构阻抗不匹配,转换是有损的。 所以我会建议反对这种格式到格式的转换。
但是,如果你这样做,首先从json转换为对象,然后从对象转换为xml(反之亦然)。 做直接的转变会导致丑陋的产出,信息的丧失,或者两者兼而有之。
我搜索了很长时间,以找到接受的解决方案的替代代码,希望不使用外部程序集/项目。 我想到了以下感谢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,有很多方法可以做相反的事情。
这里是完整的C#代码来将XML转换为JSON
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" }}
试试这个功能。 我只是写了,没有太多的机会去测试,但是我的初步测试是有希望的。
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; }
下面是一个简单的代码片段,它将XmlNode(递归)转换为散列表,并将同一子代的多个实例分组到一个数组中(如ArrayList)。 Hashtable通常被大多数JSON库接受转换成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; }
我喜欢大卫布朗说,但我有以下例外。
$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>