从XML转换到JSON的方法有多种, 不过都要依赖第三方的库来实现转化,不过有了eBay提供的xml-2-json.xlst模板,你会发现转换原来很轻松.
xml-2-json.xslt的代码大致如下(稍做了点改动):
<?
xml version="1.0" encoding="UTF-8"
?>
< xsl:stylesheet version ="1.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" xmlns:fo ="http://www.w3.org/1999/XSL/Format" xmlns:ebl ="urn:ebay:apis:eBLBaseComponents" exclude-result-prefixes ="ebl" >
<!-- ====================================================================================
Original version by : Holten Norris ( holtennorris at yahoo.com )
Current version maintained by: Alan Lewis (alanlewis at gmail.com)
Thanks to Venu Reddy from eBay XSLT team for help with the array detection code
Protected by CDDL open source license.
Transforms XML into JavaScript objects, using a JSON format.
===================================================================================== -->
< xsl:output method ="text" encoding ="UTF-8" />
< xsl:template match ="*" >
< xsl:param name ="recursionCnt" > 0 </ xsl:param >
< xsl:param name ="isLast" > 1 </ xsl:param >
< xsl:param name ="inArray" > 0 </ xsl:param >
< xsl:if test ="$recursionCnt=0" >
< xsl:text > json = { </ xsl:text >
</ xsl:if >
<!-- test what type of data to output -->
< xsl:variable name ="elementDataType" >
< xsl:value-of select ="number(text())" />
</ xsl:variable >
< xsl:variable name ="elementData" >
<!-- TEXT ( use quotes ) -->
< xsl:if test ="string($elementDataType) ='NaN'" >
< xsl:if test ="boolean(text())" >
" < xsl:value-of select ="text()" /> "
</ xsl:if >
</ xsl:if >
<!-- NUMBER (no quotes ) -->
< xsl:if test ="string($elementDataType) !='NaN'" >
< xsl:value-of select ="text()" />
</ xsl:if >
<!-- NULL -->
< xsl:if test ="not(*)" >
< xsl:if test ="not(text())" >
null
</ xsl:if >
</ xsl:if >
</ xsl:variable >
< xsl:variable name ="hasRepeatElements" >
< xsl:for-each select ="*" >
< xsl:if test ="name() = name(preceding-sibling::*) or name() = name(following-sibling::*)" >
true
</ xsl:if >
</ xsl:for-each >
</ xsl:variable >
< xsl:if test ="not(count(@*) > 0)" >
" < xsl:value-of select ="local-name()" /> ": < xsl:value-of select ="$elementData" />
</ xsl:if >
< xsl:if test ="count(@*) > 0" >
" < xsl:value-of select ="local-name()" /> ": {
"content": < xsl:value-of select ="$elementData" />
< xsl:for-each select ="@*" >
< xsl:if test ="position()=1" > , </ xsl:if >
<!-- test what type of data to output -->
< xsl:variable name ="dataType" >
< xsl:value-of select ="number(.)" />
</ xsl:variable >
< xsl:variable name ="data" >
<!-- TEXT ( use quotes ) -->
< xsl:if test ="string($dataType) ='NaN'" >
" < xsl:value-of select ="current()" /> " </ xsl:if >
<!-- NUMBER (no quotes ) -->
< xsl:if test ="string($dataType) !='NaN'" >
< xsl:value-of select ="current()" />
</ xsl:if >
</ xsl:variable >
< xsl:value-of select ="local-name()" /> : < xsl:value-of select ="$data" />
< xsl:if test ="position() !=last()" > , </ xsl:if >
</ xsl:for-each >
}
</ xsl:if >
< xsl:if test ="not($hasRepeatElements = '')" >
[{
</ xsl:if >
< xsl:for-each select ="*" >
< xsl:if test ="position()=1" >
< xsl:if test ="$hasRepeatElements = ''" >
< xsl:text > { </ xsl:text >
</ xsl:if >
</ xsl:if >
< xsl:apply-templates select ="current()" >
< xsl:with-param name ="recursionCnt" select ="$recursionCnt+1" />
< xsl:with-param name ="isLast" select ="position()=last()" />
< xsl:with-param name ="inArray" select ="not($hasRepeatElements = '')" />
</ xsl:apply-templates >
< xsl:if test ="position()=last()" >
< xsl:if test ="$hasRepeatElements = ''" >
< xsl:text > } </ xsl:text >
</ xsl:if >
</ xsl:if >
</ xsl:for-each >
< xsl:if test ="not($hasRepeatElements = '')" >
}]
</ xsl:if >
< xsl:if test ="not( $isLast )" >
< xsl:if test ="$inArray = 'true'" >
< xsl:text > } </ xsl:text >
</ xsl:if >
,
< xsl:if test ="$inArray = 'true'" >
< xsl:text > { </ xsl:text >
</ xsl:if >
</ xsl:if >
< xsl:if test ="$recursionCnt=0" > }; </ xsl:if >
</ xsl:template >
</ xsl:stylesheet >
< xsl:stylesheet version ="1.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" xmlns:fo ="http://www.w3.org/1999/XSL/Format" xmlns:ebl ="urn:ebay:apis:eBLBaseComponents" exclude-result-prefixes ="ebl" >
<!-- ====================================================================================
Original version by : Holten Norris ( holtennorris at yahoo.com )
Current version maintained by: Alan Lewis (alanlewis at gmail.com)
Thanks to Venu Reddy from eBay XSLT team for help with the array detection code
Protected by CDDL open source license.
Transforms XML into JavaScript objects, using a JSON format.
===================================================================================== -->
< xsl:output method ="text" encoding ="UTF-8" />
< xsl:template match ="*" >
< xsl:param name ="recursionCnt" > 0 </ xsl:param >
< xsl:param name ="isLast" > 1 </ xsl:param >
< xsl:param name ="inArray" > 0 </ xsl:param >
< xsl:if test ="$recursionCnt=0" >
< xsl:text > json = { </ xsl:text >
</ xsl:if >
<!-- test what type of data to output -->
< xsl:variable name ="elementDataType" >
< xsl:value-of select ="number(text())" />
</ xsl:variable >
< xsl:variable name ="elementData" >
<!-- TEXT ( use quotes ) -->
< xsl:if test ="string($elementDataType) ='NaN'" >
< xsl:if test ="boolean(text())" >
" < xsl:value-of select ="text()" /> "
</ xsl:if >
</ xsl:if >
<!-- NUMBER (no quotes ) -->
< xsl:if test ="string($elementDataType) !='NaN'" >
< xsl:value-of select ="text()" />
</ xsl:if >
<!-- NULL -->
< xsl:if test ="not(*)" >
< xsl:if test ="not(text())" >
null
</ xsl:if >
</ xsl:if >
</ xsl:variable >
< xsl:variable name ="hasRepeatElements" >
< xsl:for-each select ="*" >
< xsl:if test ="name() = name(preceding-sibling::*) or name() = name(following-sibling::*)" >
true
</ xsl:if >
</ xsl:for-each >
</ xsl:variable >
< xsl:if test ="not(count(@*) > 0)" >
" < xsl:value-of select ="local-name()" /> ": < xsl:value-of select ="$elementData" />
</ xsl:if >
< xsl:if test ="count(@*) > 0" >
" < xsl:value-of select ="local-name()" /> ": {
"content": < xsl:value-of select ="$elementData" />
< xsl:for-each select ="@*" >
< xsl:if test ="position()=1" > , </ xsl:if >
<!-- test what type of data to output -->
< xsl:variable name ="dataType" >
< xsl:value-of select ="number(.)" />
</ xsl:variable >
< xsl:variable name ="data" >
<!-- TEXT ( use quotes ) -->
< xsl:if test ="string($dataType) ='NaN'" >
" < xsl:value-of select ="current()" /> " </ xsl:if >
<!-- NUMBER (no quotes ) -->
< xsl:if test ="string($dataType) !='NaN'" >
< xsl:value-of select ="current()" />
</ xsl:if >
</ xsl:variable >
< xsl:value-of select ="local-name()" /> : < xsl:value-of select ="$data" />
< xsl:if test ="position() !=last()" > , </ xsl:if >
</ xsl:for-each >
}
</ xsl:if >
< xsl:if test ="not($hasRepeatElements = '')" >
[{
</ xsl:if >
< xsl:for-each select ="*" >
< xsl:if test ="position()=1" >
< xsl:if test ="$hasRepeatElements = ''" >
< xsl:text > { </ xsl:text >
</ xsl:if >
</ xsl:if >
< xsl:apply-templates select ="current()" >
< xsl:with-param name ="recursionCnt" select ="$recursionCnt+1" />
< xsl:with-param name ="isLast" select ="position()=last()" />
< xsl:with-param name ="inArray" select ="not($hasRepeatElements = '')" />
</ xsl:apply-templates >
< xsl:if test ="position()=last()" >
< xsl:if test ="$hasRepeatElements = ''" >
< xsl:text > } </ xsl:text >
</ xsl:if >
</ xsl:if >
</ xsl:for-each >
< xsl:if test ="not($hasRepeatElements = '')" >
}]
</ xsl:if >
< xsl:if test ="not( $isLast )" >
< xsl:if test ="$inArray = 'true'" >
< xsl:text > } </ xsl:text >
</ xsl:if >
,
< xsl:if test ="$inArray = 'true'" >
< xsl:text > { </ xsl:text >
</ xsl:if >
</ xsl:if >
< xsl:if test ="$recursionCnt=0" > }; </ xsl:if >
</ xsl:template >
</ xsl:stylesheet >
从上面的代码可以看出,只要给出相应的XML在应用此XLST样式就可以实现转化了。
不过为了方便,还是封装一层,以便我们能更好地在.NET下完成任务:
首先,是一个通用的转换方法,它可以读出流,然后应用XSLT样式:
private
static
string
XML2JSon(Stream rd,
int
type)
... {
XmlDocument doc = new XmlDocument();
rd.Position=0;
doc.Load(rd);
XmlElement root = doc.DocumentElement;
XmlNodeList nl;
if(type == 0)
nl = root.SelectNodes("//Table1");
else
nl = root.ChildNodes;
XmlDocument srcdoc = new XmlDocument();
string temp =null;
foreach(XmlNode xn in nl)
...{
if(type==0)
temp += xn.InnerXml;
else
temp += xn.OuterXml;
}
temp = "<result>" + temp + "</result>";
srcdoc.InnerXml = temp;
XPathNavigator nav = srcdoc.CreateNavigator();
XslTransform xt = new XslTransform();
string path = ConfigurationSettings.AppSettings["ServerPath"];
xt.Load(path + "css/xml-2-json.xsl");
Stream w = new MemoryStream();
XmlTextWriter wr = new XmlTextWriter(w,Encoding.GetEncoding("UTF-8"));
xt.Transform(nav,null,w,null);
w.Position = 0;
StreamReader tr = new StreamReader(w);
string str = tr.ReadToEnd();
w.Close();
tr.Close();
return str;
}
... {
XmlDocument doc = new XmlDocument();
rd.Position=0;
doc.Load(rd);
XmlElement root = doc.DocumentElement;
XmlNodeList nl;
if(type == 0)
nl = root.SelectNodes("//Table1");
else
nl = root.ChildNodes;
XmlDocument srcdoc = new XmlDocument();
string temp =null;
foreach(XmlNode xn in nl)
...{
if(type==0)
temp += xn.InnerXml;
else
temp += xn.OuterXml;
}
temp = "<result>" + temp + "</result>";
srcdoc.InnerXml = temp;
XPathNavigator nav = srcdoc.CreateNavigator();
XslTransform xt = new XslTransform();
string path = ConfigurationSettings.AppSettings["ServerPath"];
xt.Load(path + "css/xml-2-json.xsl");
Stream w = new MemoryStream();
XmlTextWriter wr = new XmlTextWriter(w,Encoding.GetEncoding("UTF-8"));
xt.Transform(nav,null,w,null);
w.Position = 0;
StreamReader tr = new StreamReader(w);
string str = tr.ReadToEnd();
w.Close();
tr.Close();
return str;
}
然后定义三个重载方法,来负责转换或序列化对象生成XML:
转换DataSet
public
static
string
Convert(DataSet ds)
... {
MemoryStream ms = new MemoryStream();
XmlTextWriter tw = new XmlTextWriter(ms,Encoding.UTF8);
ds.WriteXml(ms);
string str = XML2JSon(ms,0);
... {
MemoryStream ms = new MemoryStream();
XmlTextWriter tw = new XmlTextWriter(ms,Encoding.UTF8);
ds.WriteXml(ms);
string str = XML2JSon(ms,0);