从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);
ds.Dispose();
ms.Close();
return str;
}
... {
MemoryStream ms = new MemoryStream();
XmlTextWriter tw = new XmlTextWriter(ms,Encoding.UTF8);
ds.WriteXml(ms);
string str = XML2JSon(ms,0);
ds.Dispose();
ms.Close();
return str;
}
转换Model
public
static
string
Convert(
object
model)
{
XmlSerializer xmls = new XmlSerializer(model.GetType());
MemoryStream ms = new MemoryStream();
xmls.Serialize(ms,model);
string str = XML2JSon(ms, 1 );
ms.Close();
return str;
}
{
XmlSerializer xmls = new XmlSerializer(model.GetType());
MemoryStream ms = new MemoryStream();
xmls.Serialize(ms,model);
string str = XML2JSon(ms, 1 );
ms.Close();
return str;
}
直接读XML并转换
public
static
string
Convert(
string
XMLFilename)
... {
FileStream fs = new FileStream(XMLFilename,FileMode.Open,FileAccess.Read);
string str = XML2JSon(fs,1);
fs.Close();
return str;
}
... {
FileStream fs = new FileStream(XMLFilename,FileMode.Open,FileAccess.Read);
string str = XML2JSon(fs,1);
fs.Close();
return str;
}
然后我们就可以使用它了,在ashx或webservice里调用Convert方法并用Response.write方法输出,就可以得到JSON。
例如:
<?
xml version="1.0" encoding="utf-8"
?>
< root >
< styletype id ="0" imgsrc ="/fitment/images/loading/loading.gif" > 读取中....... </ styletype >
<!-- <styletype id="1" imgsrc="/fitment/images/loading/loadingbar2.gif"><![CDATA[ ]]></styletype> -->
< styletype id ="1" > <![CDATA[ 读取中....<br><img src='/fitment/images/loading/loadingbar2.gif'/> ]]> </ styletype >
</ root >
< root >
< styletype id ="0" imgsrc ="/fitment/images/loading/loading.gif" > 读取中....... </ styletype >
<!-- <styletype id="1" imgsrc="/fitment/images/loading/loadingbar2.gif"><![CDATA[ ]]></styletype> -->
< styletype id ="1" > <![CDATA[ 读取中....<br><img src='/fitment/images/loading/loadingbar2.gif'/> ]]> </ styletype >
</ root >
输出成
json
=
{
"
result
"
: [{
"
styletype
"
: {
"
content
"
:
"
读取中.......
"
,id:
0
, imgsrc:
"
/fitment/images/loading/loading.gif
"
} } , {
"
styletype
"
: {
"
content
"
:
"
读取中....
" ,id: 1 } }] };
" ,id: 1 } }] };
OK,这样我们就可以通过多种方式读出此JSON来处理我们的数据了