手上有個程式要處理類似以下的簡單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 比也是輸慘慘...

Post a comment