Friday, November 17, 2006 - 文章

KB-令人驚豔的.NET 2.0 XmlDocument
手上有個程式要處理類似以下的簡單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,不必擔心遭天讉。

搜尋

Go

<November 2006>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication