KB-令人驚豔的.NET 2.0 XmlDocument
1 |
手上有個程式要處理類似以下的簡單XML,DocumentElement之下只有一層,約20個ChildNodes:
<FormContext Id=""6E03A8E3614C4946825D8705CF24A472"">
<SameDept>Y</SameDept>
<AppMgr>0023456</AppMgr>
<CPWin>0045387</CPWin>
<PTMan>0012083</PTMan>
<ptApplyDate>2006/11/16</ptApplyDate>
<ptApplyerName>王建民</ptApplyerName>
.... 省略 ....
<ptInDate>2006/11/17</ptInDate>
<ptAcctOut>0000000</ptAcctOut>
<ptDeptOut></ptDeptOut>
<ptAcctIn>0000000</ptAcctIn>
<ptDeptIn></ptDeptIn>
</FormContext>
我需要將以上XML中各ChildNode資料取出,而運算頻率還挺高的,要用哪種方法就得講究點。在刻板印象中,我們一直被教導著(尤其是考過MCSD的人),XmlDocument很笨重,如果只是要查詢,記得要用XPathNavigator取代(雖然語法上囉嗦了許多!)。基於對XmlDocument的不信任感,我甚至想用RegularExpression解析,看看會不會快一點,於是順手做了以下的Benchmark:
string x= @"
<FormContext Id=""6E03A8E3614C4946825D8705CF24A472"">
<SameDept>Y</SameDept>
<AppMgr>0011456</AppMgr>
...略...
<ptDeptIn></ptDeptIn>
</FormContext>
";
int totalCount = 50000;
for (int testMode = 1; testMode <= 3; testMode++)
{
Response.Write("<hr><b>");
if (testMode == 1) Response.Write("XmlDocument");
if (testMode == 2) Response.Write("XmlPathNavigator");
if (testMode == 3) Response.Write("RegularExpression");
Response.Write("</b>");
Response.Write("<br>Total Count=" + totalCount);
DateTime st = DateTime.Now;
Hashtable ht = new Hashtable();
for (int i = 0; i < totalCount; i++)
{
ht.Clear();
switch (testMode)
{
case 1: //XmlDocument
XmlDocument xd = new XmlDocument();
xd.LoadXml(x);
foreach (XmlNode n in xd.DocumentElement.ChildNodes)
ht.Add(n.Name, n.InnerText);
break;
case 2: //XmlNavigator
XmlTextReader xtr = new XmlTextReader(new StringReader(x));
XPathDocument xpd = new XPathDocument(xtr);
XPathNavigator xpn = xpd.CreateNavigator();
xpn.MoveToFirstChild();
XPathNodeIterator xpni = xpn.SelectChildren(XPathNodeType.Element);
while (xpni.MoveNext())
ht.Add(xpni.Current.Name, xpni.Current.Value);
break;
case 3: //Regular Expression
foreach (Match m in Regex.Matches(x.Substring(1), "(?ims)<(?<tagName>.+?)>(?<text>.*?)</.+?>"))
ht.Add(m.Groups["tagName"].Value, m.Groups["text"].Value);
break;
}
}
Response.Write("<br>Get Nodes Count=" + ht.Count);
TimeSpan ts = DateTime.Now - st;
Response.Write("<br>Duration=" + ts.Seconds + "." + ts.Milliseconds);
}
以上的測試方法是用XmlDocument/XmlXPathNavigator/RegularExpression三種方式取出22個ChildNode的資料,存入Hashtable,反覆跑50,000次,並記錄執行時間(Duration單位為秒)。結果讓我大吃一驚!
XmlDocument Total Count=50000 Hashtable Count=22 Duration=3.468 | XmlPathNavigator Total Count=50000 Hashtable Count=22 Duration=3.546 | RegularExpression Total Count=50000 Hashtable Count=22 Duration=9.593 |
啥?? XmlDocument比XmlXPathNavigator還快,而RegularExpression慢了近三倍! 難道我被騙了這麼多年??? 忽然想到曾經讀過文章說.NET 2.0對XmlDocument做了改善,於是將同樣的程式搬到1.1上再跑一次:
XmlDocument Total Count=50000 Get Nodes Count=22 Duration=11.781 | XmlPathNavigator Total Count=50000 Get Nodes Count=22 Duration=4.750 | RegularExpression Total Count=50000 Get Nodes Count=22 Duration=10.859 |
原來我並沒有被騙,只是時代改變了~~~ 在.NET 1.1的時代,XmlDocument真的比XmlXPathNavigator慢了兩倍以上,也輸給RegularExpression! 而到了.NET 2.0,XmlDocument甚至可能比XmlXPathNavigator還快! 而在2.0的執行的速度也比在1.1跑快26%!
不過,大家要留意,在我的測試中,XML並不大,而且已經以字串形式存在。如果是巨大而複雜的XML檔,結果可能會有差異! 至少,在我這次的應用中,應該可以安心地使用XmlDocument Parse XML,不必擔心遭天讉。
Comments
# by chicken
.net 2.0 xml 方面改進很大, 看起來 m$ 也是拼下去了... 整個 .net 到處都在用 xml, 拼下去 m$ 是最大贏家啊..<BR/><BR/>古早前 .net 2.0 剛出來我也寫過類似的 testing, 不過目標放在 xslt 上面... 當時跟 1.1 的 XslTransform 簡直不能比, 隨便都有 500% ~ 800% 的效能增進<BR/><BR/>不過不完全是 .net 2.0 太強, 原本 1.1 的 xslt engine 太慢也是原因之一, 1.1 跟 MSXML 比也是輸慘慘...