• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            cexer

            cexer
            posts - 12, comments - 334, trackbacks - 0, articles - 0
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            寫(xiě)了一個(gè)mircro XML解析器,附源代碼

            Posted on 2008-08-22 16:56 cexer 閱讀(4460) 評(píng)論(20)  編輯 收藏 引用 所屬分類(lèi): utility

            轉(zhuǎn)帖請(qǐng)注明出處 http://www.shnenglu.com/cexer/archive/2008/08/18/59285.html

            不喜歡看人廢話(huà)喜歡直奔主題的是同學(xué)可以直接: goto 附件下載


              mirco 的意思是比 tiny 還要 tiny。

              GUI 模板用 XML 做是最合適的。方便嵌入腳本,方便編輯修改,方便嵌入皮膚描述,用 XML 做模板,寫(xiě)起 GUI 編輯器也要方便得多。

              以前幾個(gè)的 GUI 模板解析器用的是 MSXML 來(lái)實(shí)現(xiàn)的,不過(guò)它提供的接口字符串類(lèi)型全是 BSTR,自己的接口又是 TCHAR*,每一次的調(diào)用都會(huì)有一次字符串轉(zhuǎn)換,效率很低。而且一想到代碼里有 QueryInteface,AddRef,Release ,心里就不踏實(shí),擔(dān)心吊膽的。

              于是又打算用 TinyXML,看了幾遍代碼,發(fā)現(xiàn)它對(duì)寬字符集的支持有些古怪。代碼里其它的雜七雜八的東西有點(diǎn)多,代碼風(fēng)格什么的也不大喜歡。

              于是自己寫(xiě)了一個(gè)簡(jiǎn)單的,雖然有錯(cuò)誤檢測(cè)機(jī)制,不過(guò)沒(méi)有提供查詢(xún)接口,因?yàn)檫@樣我覺(jué)得使接口不整潔。其實(shí)要知道 XML 哪里出錯(cuò)了很簡(jiǎn)單,隨便拿個(gè)瀏覽器打開(kāi)就行了,提示得非常詳細(xì)。不過(guò)以后可能會(huì)根據(jù)需要添加上。XPATH 支持也是如此。接口函數(shù)全部使用 UNICODE。

             

            測(cè)試代碼:

               1: // cexer
               2: #include "./include/XML/xmlfile.h"
               3: #include "./include/XML/xmlelement.h"
               4: #include "./include/XML/xmldeclaration.h"
               5: #include "./include/XML/xmlunknown.h"
               6: #include "./include/XML/xmlcomment.h"
               7: #include "./include/XML/xmltext.h"
               8: #include "./include/XML/xmlattribute.h"
               9:  
              10: using namespace cexer;
              11: using namespace cexer::xml;
              12:  
              13:  
              14: // c++ std
              15: #include <iostream>
              16: using namespace std;
              17:  
              18:  
              19: int wmain( int argc,WCHAR** argv )
              20: {
              21:     wcout.imbue( std::locale("chs") );
              22:  
              23:     XmlFile document( L"./XMLs/utf16le_ns.xml" );
              24:     if ( !document.load() )
              25:     {
              26:         wcout<<L"解析失敗"<<endl;
              27:         return 0;
              28:     }
              29:  
              30:     XmlElement* root = document.element();
              31:     if ( !root )
              32:     {
              33:         wcout<<L"沒(méi)有找到根結(jié)點(diǎn)"<<endl;
              34:         return 0;
              35:     }
              36:  
              37:     wcout<<root->name()<<endl;
              38:  
              39:  
              40:     XmlNode* firstChild = root->firstChild();
              41:     if ( !firstChild )
              42:     {
              43:         wcout<<L"沒(méi)有子結(jié)點(diǎn)"<<endl;
              44:         return 0;
              45:     }
              46:  
              47:     XmlDeclaration* declar = xml_cast<XmlDeclaration*>( firstChild );
              48:     if ( !declar )
              49:     {
              50:         wcout<<L"第一個(gè)子結(jié)點(diǎn)不是聲明"<<endl;
              51:     }
              52:     else
              53:     {
              54:         wcout<<L"第一個(gè)節(jié)點(diǎn)是聲明"<<endl;
              55:         wcout<<L"version = "<<declar->version()<<endl;
              56:         wcout<<L"encoding = "<<declar->encoding()<<endl;
              57:         wcout<<L"standalone = "<<declar->standalone()<<endl;
              58:     }
              59:  
              60:     XmlComment* comment = xml_cast<XmlComment*>( firstChild->next() );
              61:     if ( !comment )
              62:     {
              63:         wcout<<L"第二個(gè)子結(jié)點(diǎn)不是注釋"<<endl;
              64:     }
              65:     else
              66:     {
              67:         wcout<<L"第二個(gè)結(jié)點(diǎn)是注釋?zhuān)?<<comment->value()<<endl;
              68:     }
              69:  
              70:     XmlElement* window = root->element( L"window" );
              71:     if ( !window )
              72:     {
              73:         wcout<<L"沒(méi)有找到window元素結(jié)點(diǎn)"<<endl;
              74:         return 0;
              75:     }
              76:     wcout<<window->attributeValue( L"text" )<<endl;
              77:  
              78:  
              79:     XmlElement* nextWindow = window->nextElement( L"window" );
              80:     if ( !nextWindow )
              81:     {
              82:         wcout<<L"沒(méi)有找到后面的window元素結(jié)點(diǎn)"<<endl;
              83:     }
              84:     else
              85:     {
              86:         wcout<<L"后面還有一個(gè)window元素結(jié)點(diǎn) ";
              87:         wcout<<nextWindow->attributeValue(_T("name"))<<endl;
              88:     }
              89:  
              90:     XmlElement* panel = window->element( L"panel" );
              91:     if ( panel )
              92:     {
              93:         wcout<<panel->attributeValue( L"caption" )<<endl;
              94:     }
              95:  
              96:     window->setAttribute( L"styleAdd",L"WS_VISIBLE" );
              97:     window->setAttribute( L"styleRemove",L"\";<>=&\"" );
              98:  
              99:     if ( !document.save( L"./XMLs/modified/utf16le_ns.xml" ) )
             100:     {    
             101:         wcout<<L"保存失敗"<<endl;
             102:     }
             103:  
             104:     return 0;
             105: }

             

            編碼支持:

              因?yàn)閮?nèi)部使用 MultiBytesToWideChar 和 WideCharToMultiBytes 來(lái)實(shí)現(xiàn)字符集/編碼的操作,因此對(duì)字符集/編碼的支持很靈活,能夠支持以上兩個(gè)函數(shù)支持的所有編碼,只需簡(jiǎn)單的修改即可添加新的支持。預(yù)置了幾種編碼支持:

            1. UTF-16LE(UNICODE)
            2. GBK
            3. BIG5
            4. GB2312
            5. UTF-7
            6. UTF-8

              對(duì)于沒(méi)有編碼聲明并且沒(méi)有文件頭簽名文件,都視為 UTF-8 編碼。以上的代碼當(dāng)中的 XML 文件就是一個(gè)沒(méi)有簽名,沒(méi)有聲明的 UTF-16LE 編碼的 XML 文件。

              TinyXML 內(nèi)部解析字符串全是以 char*  類(lèi)型來(lái)解析,只支持多字節(jié)編碼如 UTF-8,ASCII,不支持 UNICODE 編碼。如對(duì)中文的支持就比較古怪,如果 XML 以 UTF-8 格式保存,則設(shè)置“值”的時(shí)候必須自己把字符串轉(zhuǎn)換為 UTF-8 再設(shè)置,而在取得值以后,則必須自己將它們從 UTF-8 轉(zhuǎn)換成 UNICODE 或 ASCII,否則就是亂碼。

              主要是 TinyXML 為了跨平臺(tái),所以沒(méi)有像 MultiBytesToWideChar  和 WideCharToMultiBytes  這種函數(shù)的直接支持。不過(guò)如果是為了跨平臺(tái),這兩個(gè)函數(shù)也可以考慮自己實(shí)現(xiàn)。

             

            節(jié)點(diǎn)類(lèi)型轉(zhuǎn)換:

              因?yàn)樵趦?nèi)存當(dāng)中,元素,注釋?zhuān)谋荆暶鞯冉Y(jié)點(diǎn)都是存儲(chǔ)為一個(gè)基類(lèi)的指針,因此在使用的時(shí)候必須要有一個(gè)類(lèi)型轉(zhuǎn)換的動(dòng)作。也有一些 XML 解析器比較簡(jiǎn)單,其中只有文檔,元素,屬性這三種結(jié)點(diǎn),內(nèi)存當(dāng)中存的全部都是元素集合,元素當(dāng)中再存有屬性集合,用不著類(lèi)型轉(zhuǎn)換,不過(guò)這種 XML 將 XML 讀入內(nèi)存再存入磁盤(pán)文件當(dāng)中時(shí),會(huì)丟失掉 XML 文件原有的格式。

              TinyXML 在內(nèi)存當(dāng)中所有的結(jié)點(diǎn)(除屬性)都以基類(lèi) TiXmlNode 指針的形式存放 ,從一個(gè) TiXmlNode* 進(jìn)行類(lèi)型轉(zhuǎn)的方法是這樣的:

              首先在基 TiXmlBase 聲明一組虛函數(shù)

               1: class TiXmlNode
               2: {
               3:     virtual TiXmlDocument*   ToDocument()    { return 0; }
               4:     virtual TiXmlElement*    ToElement()        { return 0; }
               5:     virtual TiXmlComment*    ToComment()     { return 0; }
               6:     virtual TiXmlUnknown*    ToUnknown()        { return 0; }
               7:     virtual TiXmlText*       ToText()        { return 0; }
               8:     virtual TiXmlDeclaration*    ToDeclaration() { return 0; }
               9: };

             
              然后在子類(lèi)當(dāng)中各自重寫(xiě)向自己類(lèi)型轉(zhuǎn)換的那一個(gè)虛函數(shù)。如在 XmlElement 和 XmlComment 當(dāng)中:

               1: class XmlElement
               2: {
               3:     virtual TiXmlElement*    ToElement()        { return this; }
               4: };
               5:  
               6: class XmlComment
               7: {
               8:     virtual TiXmlComment*    ToComment()     { return this; }
               9: };


              這樣做很方便,不過(guò)如果要寫(xiě)一個(gè)新的 XML 結(jié)點(diǎn)類(lèi)型,就比較麻煩了,必須重新修改基類(lèi) TiXmlNode 的代碼,整個(gè) XML 解析器的代碼都得重新編譯一遍。

              我則借用了 COM 的 Queryinterface 的方式。在基類(lèi) XmlCastable 當(dāng)中聲明了一個(gè)虛函數(shù) query,任意結(jié)點(diǎn)調(diào)用這個(gè)函數(shù),輸入一個(gè)類(lèi)型,若該結(jié)點(diǎn)是這個(gè)類(lèi)型,那么就輸出指針的值并返回 true,否則輸出 NULL 并返回 false。

               1: class XmlCastable
               2: {
               3:     virtual bool query( XmlType destType,void** ppvoid ) = 0;
               4: };
               5:  


              如在 XmlNamedNode  當(dāng)中:

               1: bool XmlNamedNode::query( XmlType type,void** pptr )
               2: {
               3:     if ( !pptr )
               4:     {
               5:         return false;
               6:     }
               7:  
               8:     *pptr = NULL;
               9:  
              10:     if ( XmlNamedNode::s_type == type )
              11:     {
              12:         *pptr = this;
              13:         return true;
              14:     }
              15:  
              16:     return false;
              17: }


              不過(guò)這樣使用起來(lái)會(huì)相當(dāng)?shù)芈闊詫?xiě)了一個(gè)輔助函數(shù) xml_cast,可以對(duì) XmlNode* 這樣調(diào)用:

               1: XmlNode* node = ...;
               2: XmlElement* element = xml_cast<XmlElement*>( node );
               3: XmlComment* comment = xml_cast<XmlComment*>( node );


            類(lèi)結(jié)構(gòu):

               1: // 給函數(shù) xml_cast 提供結(jié)點(diǎn)類(lèi)型的轉(zhuǎn)換能力
               2: class XmlCastable
               3: {...};
               4:  
               5: // 除了屬性結(jié)點(diǎn)(XmlAttribute)外,所有結(jié)點(diǎn)類(lèi)型的基礎(chǔ)
               6: class XmlNode:public XmlCastable
               7: {...};
               8:  
               9: // 含有子結(jié)點(diǎn)的結(jié)點(diǎn)如:元素(XmlElement),文檔(XmlDocument)
              10: class XmlParentNode:public XmlNode
              11: {...};
              12:  
              13: // 有名字的結(jié)點(diǎn)如:元素(XmlElement),屬性(XmlAttribute)
              14: class XmlNamedNode:public XmlCastable
              15: {...};
              16:  
              17: // 有值的結(jié)點(diǎn)如:屬性(XmlAttribute),文本(XmlText),注釋(XmlComment),未知(XmlUnknown)
              18: class XmlValueNode:public XmlCastable
              19: {...};
              20:  
              21:  
              22: // XML聲明 <?xml ..... ?>
              23: class XmlDeclaration:public XmlNode
              24: {...};
              25:  
              26:  
              27: // XML注釋結(jié)點(diǎn)<!-- ..... -->
              28: class XmlComment:public XmlNode
              29:                  ,public XmlValueNode
              30: {...};
              31:  
              32:  
              33: // XML文本結(jié)點(diǎn) [文本] 及 <![CDATA[...]]>
              34: class XmlText:public XmlNode
              35:               ,public XmlValueNode
              36: {...};
              37:  
              38: // XML文檔結(jié)點(diǎn)
              39: class XmlDocument:public XmlParentNode
              40: {...};
              41:  
              42: // XML元素結(jié)點(diǎn)
              43: class XmlElement:public XmlParentNode
              44:                  ,public XmlNamedNode
              45: {...};
              46:  
              47: // XML元素屬性
              48: class XmlAttribute:public XmlNamedNode
              49:                    ,public XmlValueNode
              50: {...};
              51:  
              52: // 解析器暫不支持的XML結(jié)點(diǎn)如
              53: //    <!DOCTYPE PLAY SYSTEM 'play.dtd'>
              54: //    <!ELEMENT title (#PCDATA)>
              55: //    <!ELEMENT books (title,authors)>
              56: class XmlUnknown:public XmlNode
              57:                  ,public XmlValueNode
              58: {...};
              59:  
              60:  


            附件下載:

              從 cexer 的庫(kù)當(dāng)中把 xml 解析器剝離出來(lái)放上來(lái)。希望大家也都積極踴躍地共享代碼。(注:還沒(méi)有怎么詳細(xì)測(cè)試,切不可用于重要的項(xiàng)目如國(guó)防工程火箭發(fā)射工程之類(lèi)的,崩潰死機(jī)核彈爆炸什么的本人概不負(fù)責(zé)。。。。)

            點(diǎn)擊下載

            Feedback

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 17:55 by 陳梓瀚(vczh)
            http://www.shnenglu.com/vczh/archive/2008/06/28/54871.html

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 18:00 by 陳梓瀚(vczh)
            話(huà)說(shuō)我的庫(kù)的接口完全是Utf-16字符串的,然后我有一個(gè)Mbcs字符串類(lèi),倆能互轉(zhuǎn)。所以用我的庫(kù)的人要么用Utf-16,要么在每一個(gè)參數(shù)和返回值那里都去轉(zhuǎn)。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 18:01 by cexer
            @陳梓瀚(vczh)
            真是牛人,不過(guò)你的代碼風(fēng)格我不喜歡哈。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 18:02 by cexer
            @陳梓瀚(vczh)
            話(huà)說(shuō)我的庫(kù)的接口完全是Utf-16字符串的,然后我有一個(gè)Mbcs字符串類(lèi),倆能互轉(zhuǎn)。所以用我的庫(kù)的人要么用Utf-16,要么在每一個(gè)參數(shù)和返回值那里都去轉(zhuǎn)。

            一樣的哈。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 18:04 by 陳梓瀚(vczh)
            我的庫(kù)一開(kāi)始的目的是僅給我個(gè)人用的。后來(lái)發(fā)exe和screenshoot發(fā)多了,有一些憤青噴我說(shuō)沒(méi)發(fā)代碼純屬炫耀,雖然對(duì)于這些人他們需要的是一個(gè)代碼的鏈接,而不是一份代碼。我就只好那么干了。因此風(fēng)格是我自己私底下用的那一套,這是歷史原因。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 18:15 by 陳梓瀚(vczh)
            話(huà)說(shuō)dynamic_cast<>在失敗的時(shí)候也是返回0,你自己寫(xiě)一個(gè)難道是為了效率?還是怕編譯器被關(guān)掉RTTI?還是其他的什么東西。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 19:00 by cexer
            @陳梓瀚(vczh)
            效率問(wèn)題。dynamic_cast<>的比較的效率和字符串比較差不多,因此。。。不過(guò)想換成使用dynamic_cast<>也容易,直接
            #define xml_cast dynamic_cast
            就行了。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 20:33 by 空明流轉(zhuǎn)
            @陳梓瀚(vczh)
            你那個(gè)歷史問(wèn)題還是解決得好,要不我用你代碼要替換vl真是替換的欲死欲活啊。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 21:13 by cexer
            @空明流轉(zhuǎn)
            系統(tǒng)懷疑你灌水,亂棒打出!

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-22 21:38 by foxtail
            就是阿,他搞個(gè)vl做什么,囧@空明流轉(zhuǎn)

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-23 00:58 by 陳梓瀚(vczh)
            因?yàn)槲乙獜?qiáng)調(diào)我是因?yàn)槟切嵡嗖砰_(kāi)源的

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-23 08:35 by 空明流轉(zhuǎn)
            你只要這個(gè)代碼不賣(mài)錢(qián),還是開(kāi)源的好。
            我拿去貼代碼還是方便許多。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-23 08:38 by 空明流轉(zhuǎn)
            話(huà)說(shuō)文本解析本來(lái)就不那么快,不在乎dynamic_cast那點(diǎn)時(shí)間的。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-23 11:43 by cexer
            @空明流轉(zhuǎn)
            節(jié)點(diǎn)的類(lèi)型轉(zhuǎn)換都是在解析完成以后的啊。如果是在循環(huán)當(dāng)中用dynamic_cast,效率還是挺低的。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼[未登錄](méi)  回復(fù)  更多評(píng)論   

            2008-08-24 10:28 by Kevin Lynx
            cppblog人才輩出,不敢說(shuō)話(huà)了。
            我是真的來(lái)灌水......

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-24 15:24 by 戴爾筆記本
             GUI 模板用 XML 做的確是最合適的。因?yàn)榉奖闱度肽_本,

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼[未登錄](méi)  回復(fù)  更多評(píng)論   

            2008-08-25 10:09 by 陳梓瀚(vczh)
            要是想寫(xiě)腳本的話(huà)直接HTML好了。你要是為了界面而往C++里面加個(gè)腳本引擎,完全是得不償失。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2008-08-25 11:28 by cexer
            @陳梓瀚(vczh)
            曾經(jīng)實(shí)現(xiàn)過(guò)類(lèi)似HTML的,加了上腳本引擎,可配置能力和二次開(kāi)發(fā)能力大大增強(qiáng),用處還是很大的。

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼[未登錄](méi)  回復(fù)  更多評(píng)論   

            2008-08-25 14:17 by 陳梓瀚(vczh)
            嗯嗯,基于這一點(diǎn)考慮我做了vczh free script 2.0,而不是做一個(gè)script for GUI framework……

            # re: 寫(xiě)了一個(gè)mircro XML解析器,附源代碼  回復(fù)  更多評(píng)論   

            2009-01-08 16:36 by 陳昕
            報(bào)告?zhèn)€bug,保存成UTF16文件的時(shí)候頭部字節(jié)錯(cuò)了,和讀取時(shí)的不一樣,并且IE打不開(kāi)保存的文件.改成和讀取時(shí)的一樣就好了.
            国产亚洲美女精品久久久| 无码人妻久久久一区二区三区 | 久久人人爽人人爽人人片AV麻豆| 久久亚洲国产成人精品性色| 久久精品亚洲AV久久久无码| 国产精品久久久久蜜芽| 久久久久国产视频电影| 亚洲欧美日韩精品久久| 国产精品18久久久久久vr| 久久精品亚洲日本波多野结衣 | 亚洲精品99久久久久中文字幕| 国内精品伊人久久久久网站| 99国内精品久久久久久久| 99久久国产热无码精品免费久久久久 | 久久国产精品77777| 久久99国内精品自在现线| 99久久人妻无码精品系列| 丰满少妇人妻久久久久久| 精品久久一区二区三区| 久久综合九色综合97_久久久| 91精品国产91久久久久久青草| 亚洲午夜精品久久久久久人妖| 日本精品久久久中文字幕| 国产AⅤ精品一区二区三区久久| 国产精品午夜久久| 久久久久九九精品影院| 婷婷久久五月天| 日韩精品久久久肉伦网站| 久久久久AV综合网成人| 久久免费美女视频| 久久久久久毛片免费看| 久久精品桃花综合| 久久婷婷成人综合色综合| 欧美日韩中文字幕久久伊人| 久久精品亚洲乱码伦伦中文| 香蕉久久夜色精品国产2020| 久久亚洲日韩精品一区二区三区| 国产精品一久久香蕉国产线看| 国内精品久久久久久久涩爱| 亚洲午夜无码AV毛片久久| 亚洲va久久久噜噜噜久久天堂|