本文旨在介紹如果通過C#將獲取到的XML文檔轉換成對應的JSON格式字符串,然后將其輸出到頁面前端,以供JavaScript代碼解析使用。或許你可以直接利用JavaScript代碼通過Ajax的方式來讀取XML,然后直接對其中的內容進行解析,這樣或許更直接一些。但本文中給出的代碼旨在說明如何通過原生的C#代碼來完成這一轉換。除此之外,你仍然可以借用一些第三方類庫或者更高級一些的.NET庫對象來實施轉換。我們來看看這里介紹的一些較為簡單的方法,但前提是你必須擁有可支持的類庫和對象以備使用。
- 使用Json.NET類庫
前提是需要首先下載和安裝Json.NET類庫,在這里可以找到http://json.codeplex.com/
下面是一個例子:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using Newtonsoft.Json; namespace JSonConverter { class Program { static void Main(string[] args) { string xml = "<Test><Name>Test class</Name><X>100</X><Y>200</Y></Test>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(doc); Console.WriteLine("XML -> JSON: {0}", json); Console.ReadLine(); } } }
- 使用.NET Framework中的JavaScriptSerializer類
首先需要確保你的工程或服務器支持.NET 4.0或以上版本的Framework,否則無法找到該類。
下面是一個例子:
using System; using System.Linq; using System.Web.Script.Serialization; using System.Xml.Linq; class Program { static void Main() { var xml = @"<Columns> <Column Name=""key1"" DataType=""Boolean"">True</Column> <Column Name=""key2"" DataType=""String"">Hello World</Column> <Column Name=""key3"" DataType=""Integer"">999</Column> </Columns>"; var dic = XDocument .Parse(xml) .Descendants("Column") .ToDictionary( c => c.Attribute("Name").Value, c => c.Value ); var json = new JavaScriptSerializer().Serialize(dic); Console.WriteLine(json); } }
其輸出結果為:{"key1":"True","key2":"Hello World","key3":"999"}
可能還會有更多的方法,這里不一一列出了。那么如何使用原生的C#代碼將XML轉換成JSON格式字符串呢?或者說該C#代碼在較低版本的.NET Framework中也可以運行呢?來看看下面的介紹吧。
Introduction
JSON是一個輕量級的數據交換格式,它可以非常容易地被頁面的JavaScript編碼為對象的形式,從而方便數據操作。
基于AJAX的頁面使用XmlHttpRequest對象從服務端接收數據來響應用戶的請求,當返回的數據是XML格式時,它可以被轉換為JSON格式的字符串從而通過JavaScript更加容易地對數據進行處理。
許多應用程序都將數據存儲為XML的格式,而且會將數據以JSON的格式發送到客戶端以做進一步處理。要實現這一點,它們必須將XML格式轉換為JSON格式。下面的ASP.NET C#代碼實現了這一過程。
Code Description
代碼中提供了一個方法XmlToJSON,可以用來將XmlDocument對象轉換為JSON字符串。代碼通過迭代每一個XML節點、屬性以及子節點,來創建對應的JSON對象。
- 代碼不會生成數字和布爾類型的值
- Xml DocumentElement對象始終會被轉換為JSON對象的member:object,它遵循下面這些規則。
- 節點的屬性會被對應地轉換為JSON對象的成員"attr_name":"attr_value"。如:
XML JSON <xx yy='nn'></xx> { "xx" : { "yy" : "nn" } } <xx yy=''></xx> { "xx" : { "yy" : "" } } - 沒有子節點、屬性和內容的節點被轉換為成員"child_name":null
XML JSON <xx/> { "xx" : null } - 沒有子節點和屬性,但是有內容的節點被轉換為成員"child_name":"child_text"
XML JSON <xx>yyy</xx> { "xx" : "yyy" } - 其它節點和屬性會被適當地轉換為"child_name":對象或者"child_name":[elements]對象數組,節點的值會被轉換為對象成員的"value",如:
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" ] } } - 字符會被安全地轉換為JSON字符串。注意該轉換不會保證你的JavaScript代碼不會受到任何注入攻擊,如果其中的內容來自于一段不安全的XML數據源的話。下面這個例子演示了字符的轉義:
XML JSON <aa>/z'z''z\yyy</aa> { "aa" : "\/z\u0027z\''z\\yyy" }
在某些特殊的環境下,例如下面的代碼,可能需要你自己對反斜線進行轉義。
string JSON = XmlToJSON(doc); JSON = JSON.Replace(@"\", @"\\");
注意,在頁面上使用任何未經檢查的XML數據時都會存在安全隱患。
Example
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>
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" } ] } ] } }
一旦JSON字符串被定義為一個JavaScript對象,如space_DOM,我們便可以在JavaScript代碼中使用下面這些對象和屬性:
- space_DOM.space.name
- space_DOM.space.frame.length
- space_DOM.space.frame[0].text.string
- space_DOM.space.frame[0].rule[0].type
你的JavaScript代碼應該可以非常靈活地應對各種情況,如成員不存在、成員只包含value、或成員是一個數組。下面這個函數可以將所有的成員轉換成一個數組,從而應對各種不同的情況。
function ObjectToArray( obj) { if( !obj) return new Array(); if( !obj.length) return new Array(obj); return obj; } space_DOM.space.frame = ObjectToArray(space_DOM.space.frame);
XmlToJSON C# code
下面給出對應的C#源代碼,通過傳入的XmlDocument對象將其轉換為對應的JSON格式字符串。
private 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 childNodeNames = new SortedList(); // 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) { 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(" }"); } // StoreChildNode: Store data associated with each nodeName // so that we know whether the nodeName is an array or not. private static void StoreChildNode(SortedList 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 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(", "); } // 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(); }
Using XmlToJSON
下面的代碼演示了如何在ASP.NET 2的頁面中使用XmlToJSON()方法。頁面上使用了ClientScriptManager對象來作為JavaScript代碼的容器。當然,你完全可以使用其它任何方式將所轉換的JSON字符串放到前端頁面上。通過下面的代碼,程序在前端頁面上調用一個名為space_processJSON的JavaScript函數,并將JSON字符串作為參數傳遞給它。
protected void Page_Load(object sender, EventArgs e) { XmlDocument doc = new XmlDocument(); try { string path = Server.MapPath("."); doc.Load(path+"whatever.xml"); } catch (Exception ex) { lblError.Text = ex.ToString(); return; } // Convert XML to a JSON string string JSON = XmlToJSON(doc); // Replace \ with \\ because string is being decoded twice JSON = JSON.Replace(@"\", @"\\"); // Insert code to process JSON at end of page ClientScriptManager cs = Page.ClientScript; cs.RegisterStartupScript(GetType(), "SpaceJSON", "space_processJSON('" + JSON + "');", true); }
來看看前端頁面上定義的這個JavaScript函數的具體內容。
<script src="space/json.js" type="text/javascript"></script> <script type="text/javascript"> function space_processJSON( JSON) { space_DOM = JSON.parseJSON(); if( !space_DOM) { alert("JSON decode error"); return; } space_DOM.space.frame = ObjectToArray(space_DOM.space.frame); space_frameCount = space_DOM.space.frame.length; //.. or whatever } </script>
文章列表