tinyxml源碼解析(中)


前言:

  之前趁着這段時間比較空閑,也因為聽聞tinyxml大名,因此就閱讀了tinyxml的源碼.在上一篇博文中<tinyxml源碼解析(上)>中對tinyxml整體架構以及其中兩個基類TiXmlBase,TiXmlNode進行了注釋解析.不過文章寫得有點啰嗦,太過詳細.因此這篇文章將提取其中的部分設計而不是對於每個函數進行注釋.

  本文將主要介紹tinyxml對於attribute的處理,各個元素類的簡單介紹以及tinyxml的整體處理流程.

正文:

  還是先回顧下之前看的tinyxml的結構圖吧.

  

  從圖上我們可以看到,TiXmlAttribute並不是繼承與TiXmlNode中,雖然其是xml的元素之一,在實現上很多也是element的葉節點,不過tinyxml並沒有這么做.可以先看下TiXmlAttribute的聲明.

View Code
 1 class TiXmlAttribute : public TiXmlBase
 2 {
 3     friend class TiXmlAttributeSet;//TiXMlAttrubteSet之后我們將會看到
 4 public:
 5     //....構造函數
 6 
 7     //返回屬性的值
 8     const char*        Name()  const        { return name.c_str(); }        
 9     const char*        Value() const        { return value.c_str(); }        
10     //....
11     //提供了比IntValue()更好的錯誤檢查.后頭還是調用了sscanf進行處理,而IntValue則是采用了atoi
12     //QueryXXXValue系列都是采用了sscanf進行處理.
13     int QueryIntValue( int* _value ) const;
14     int QueryDoubleValue( double* _value ) const;
15 
16     //設置值,對於有類型轉化的,采用了sprintf進行處理
17     void SetName( const char* _name )    { name = _name; }
18     void SetValue( const char* _value )    { value = _value; }
19 
20     void SetIntValue( int _value );                        
21     void SetDoubleValue( double _value );                
22 
23     //提供了string的版本
24     ///...
25 
26     ///簡單的比較函數
27     ///....
28     ///Parse將在下面統一講解
29     virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
30 
31 
32 private:
33     TiXmlAttribute( const TiXmlAttribute& );                // not implemented.
34     void operator=( const TiXmlAttribute& base );    // not allowed.
35 
36     TiXmlDocument*    document;    // A pointer back to a document, for error reporting.
37     TIXML_STRING name;
38     TIXML_STRING value;
39     TiXmlAttribute*    prev;
40     TiXmlAttribute*    next;
41 };

  TiXmlAttribute提供了少部分功能的轉化函數.不過特殊的是其Next函數以及Previous函數的實現比較特別.

View Code
 1 const TiXmlAttribute* TiXmlAttribute::Next() const
 2 {
 3         //這里判斷是否到尾部的方式是判斷next的成員的值
 4     if ( next->value.empty() && next->name.empty() )
 5         return 0;
 6     return next;
 7 }
 8 
 9 const TiXmlAttribute* TiXmlAttribute::Previous() const
10 {
11     // 這里也是
12     if ( prev->value.empty() && prev->name.empty() )
13         return 0;
14     return prev;
15 }

原因在於,tinyxml使用了循環雙向鏈表進行處理.看下面的TiXmlAttributeSet就可以看得出了.作者給出的理由是:他喜歡循環鏈表.另外,說明了相對於典型雙向鏈表的獨立性(這個我也沒搞明白是怎么回事).

TiXmlAttributeSet是一個工具類,其負責管理Element中的attribute.提供了添加,刪除,查找等功能,使得代碼更為簡潔.

 1 //折疊起來總是有BUG.打不開.所以就只要不折疊了...
 2 class TiXmlAttributeSet
 3 {
 4 public:
 5     //構造和析構函數,構造函數就是把sentinel的頭尾連在一起,而析構則是兩句assert,判斷是否所有元素被移除.
 6 
 7     void Add( TiXmlAttribute* attribute );
 8     void Remove( TiXmlAttribute* attribute );
 9 
10     //有元素返回,沒元素返回null
11     const TiXmlAttribute* First()    const    { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
12     TiXmlAttribute* First()                    { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
13     const TiXmlAttribute* Last() const        { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
14     TiXmlAttribute* Last()                    { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
15 
16     //查找
17     TiXmlAttribute*    Find( const char* _name ) const;
18     TiXmlAttribute* FindOrCreate( const char* _name );
19     ///stl版本
20     ///...
21 
22 private:
23     //因為TiXmlAttribute禁止復制,因此AttributeSet也禁止
24     TiXmlAttributeSet( const TiXmlAttributeSet& );    
25     void operator=( const TiXmlAttributeSet& );    
26 
27     TiXmlAttribute sentinel;//循環鏈表的頭.其目的在於做為頭和尾的區分.
28 };

 

可以看看循環鏈表的處理.

View Code
 1 void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
 2 {
 3     #ifdef TIXML_USE_STL
 4     assert( !Find( TIXML_STRING( addMe->Name() ) ) );    // Shouldn't be multiply adding to the set.
 5     #else
 6     assert( !Find( addMe->Name() ) );    // Shouldn't be multiply adding to the set.
 7     #endif
 8 
 9     addMe->next = &sentinel;
10     addMe->prev = sentinel.prev;
11 
12     sentinel.prev->next = addMe;
13     sentinel.prev      = addMe;
14 }
15 
16 void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
17 {
18     TiXmlAttribute* node;
19 
20     for( node = sentinel.next; node != &sentinel; node = node->next )
21     {
22         if ( node == removeMe )
23         {
24             node->prev->next = node->next;
25             node->next->prev = node->prev;
26             node->next = 0;
27             node->prev = 0;
28             return;
29         }
30     }
31     assert( 0 );        // we tried to remove a non-linked attribute.

在查看了attribute的處理后,我們就可以看看element的處理了.

View Code
 1 class TiXmlElement : public TiXmlNode
 2 {
 3 public:
 4     
 5     //構造,復制,析構函數
 6     ///...
 7     
 8     ///一系列的Attribute函數僅僅就是調用attributeset中的find,查找到后調用attribute的query函數
 9     ///其他都類似
10     const char* Attribute( const char* name ) const
11     {
12         const TiXmlAttribute* node = attributeSet.Find( name );
13         if ( node )
14             return node->Value();
15         return 0;
16     }
17 
18     //set函數也不例外,就是find然后set
19     void TiXmlElement::SetAttribute( const char * name, int val )
20     {    
21         TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
22         if ( attrib ) {
23             attrib->SetIntValue( val );
24         }
25     }
26     
27     //可想而知,remove肯定也是一樣的,調用attributeset的函數進行處理
28     void RemoveAttribute( const char * name );
29     
30     //獲取其中第一個文字節點
31     const char* GetText() const;
32 
33     /// 復制當前節點,重寫了TiXmlNode的純虛函數
34     virtual TiXmlNode* Clone() const;
35     //打印函數,
36     virtual void Print( FILE* cfile, int depth ) const;
37 
38     //parse函數之后統一說
39     virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
40 
41     //這部分設計的很精巧.在父類TiXmlNode中,所有的ToXXXX函數返回皆為null.而在子類中相應的重寫函數,使之轉化成為可能.而轉化成其他類的函數仍然不可以.
42     virtual const TiXmlElement*     ToElement()     const { return this; } 
43     virtual TiXmlElement*           ToElement()              { return this; } 
44 
45     virtual bool Accept( TiXmlVisitor* visitor ) const;
46 
47 protected:
48     //復制函數,提供給復制構造函數
49     void CopyTo( TiXmlElement* target ) const;
50     void ClearThis();
51     //獲取element中的值.在parse中被調用.
52     const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
53 
54 private:
55     TiXmlAttributeSet attributeSet;//管理attribute列表
56 };

剩下的幾個元素,如declaration,unknown,text,comment都和element差別不大.我們直接來看TiXmlDocument:

View Code
 1 class TiXmlDocument : public TiXmlNode
 2 {
 3 public:
 4     //構造函數
 5     TiXmlDocument()
 6     {
 7         tabsize = 4;//設定輸出tab格式
 8         useMicrosoftBOM = false;//設定是否采用ms的utf8-bom格式
 9         ClearError();
10     }
11 
12     //復制構造函數
13     TiXmlDocument( const TiXmlDocument& copy );
14     TiXmlDocument& operator=( const TiXmlDocument& copy )
15     {
16         Clear();
17         copy.CopyTo( this );//采用了private的copyTo函數
18         return *this;
19     }
20 
21     virtual ~TiXmlDocument() {}//析構沒什么好做的
22     
23     //保存和讀取文本函數,
24     bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
25     bool SaveFile( FILE* ) const;
26 
27     //分析,下面將主要分析這個函數
28     virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
29 
30     //帶格式輸出
31     virtual void Print( FILE* cfile, int depth = 0 ) const;
32     void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
33 
34     //同TiXmlElement
35     virtual const TiXmlDocument*    ToDocument()    const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
36     virtual TiXmlDocument*          ToDocument()          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
37 
38     /** Walk the XML tree visiting this node and all of its children. 
39     */
40     virtual bool Accept( TiXmlVisitor* content ) const;
41 
42 protected :
43     // 重寫的Clone函數
44     virtual TiXmlNode* Clone() const;
45     #ifdef TIXML_USE_STL
46     virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
47     #endif
48 
49 private:
50     //復制的內部函數
51     void CopyTo( TiXmlDocument* target ) const;
52 
53     bool error;
54     int  errorId;
55     TIXML_STRING errorDesc;
56     int tabsize;
57     TiXmlCursor errorLocation;//定位錯誤,包涵了行數和列數
58     bool useMicrosoftBOM;        // 使用utf-bom
59 };

 大部分只是簡單的設置,我們就着重挑幾個感興趣的看看.

首先是文件操作,LoadFile以及SaveFile

View Code
 1 //載入數據
 2 bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
 3 {
 4     if ( !file ) 
 5     {
 6         SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
 7         return false;
 8     }
 9 
10     // 初始化數據
11     Clear();
12     location.Clear();
13 
14     // 采用fseek的方式來獲取文件的大小。並且預分配數據大小,加速大文件處理
15     long length = 0;
16     fseek( file, 0, SEEK_END );
17     length = ftell( file );
18     fseek( file, 0, SEEK_SET );
19 
20     // 比較奇怪的情況。
21     if ( length <= 0 )
22     {
23         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
24         return false;
25     }
26     
27     //先new需要讀取的數據的大小.
28     char* buf = new char[ length+1 ];
29     buf[0] = 0;
30 
31     //然后一次性fread進來.
32     if ( fread( buf, length, 1, file ) != 1 ) {
33         delete [] buf;
34         SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
35         return false;
36     }
37 
38     // 統一回車符,采用p,q兩個指針進行處理.
39     //將\r\n,\n,\r統一轉化為\n.
40     const char* p = buf;    // the read head
41     char* q = buf;            // the write head
42     const char CR = 0x0d;
43     const char LF = 0x0a;
44 
45     buf[length] = 0;
46     while( *p ) {
47         assert( p < (buf+length) );
48         assert( q <= (buf+length) );
49         assert( q <= p );
50         
51         //是\r
52         if ( *p == CR ) {
53             *q++ = LF;//轉化為\n,並且判斷下一個字符,,如果是\n,則跳過
54             p++;
55             if ( *p == LF ) {        
56                 p++;
57             }
58         }
59         else {
60             *q++ = *p++;
61         }
62     }
63     assert( q <= (buf+length) );
64     *q = 0;
65 
66     Parse( buf, 0, encoding );//進行解析,生成xml節點樹
67 
68     delete [] buf;//刪除緩存的數據
69     return !Error();
70 }
71 //save相對簡單的多
72 bool TiXmlDocument::SaveFile( FILE* fp ) const
73 {
74     //如果是ms的格式,則寫一個UTF8的頭
75     if ( useMicrosoftBOM ) 
76     {
77         const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
78         const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
79         const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
80 
81         fputc( TIXML_UTF_LEAD_0, fp );
82         fputc( TIXML_UTF_LEAD_1, fp );
83         fputc( TIXML_UTF_LEAD_2, fp );
84     }
85     //然后調用Print進行格式化輸出
86     Print( fp, 0 );
87     return (ferror(fp) == 0);
88 }

接下來是我們用於輸出的Print函數:

View Code
 1 void TiXmlDocument::Print( FILE* cfile, int depth ) const
 2 {
 3     assert( cfile );
 4     for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
 5     {
 6         //使用虛函數繼承的方式,調用相應的處理函數
 7         node->Print( cfile, depth );
 8         fprintf( cfile, "\n" );
 9     }
10 }

這里用到了多態的方式,來實現相應的函數調用.

而生成所有xml樹的方法Parse也是想同的想法.

 這里就只列舉了TiXmlDocument和TiXmlElement的方法.其他的都是類似的處理方式.

View Code
  1 //在TiXmlDocument::Parse中調用,用於判斷接下來數據p中是什么類型的節點,並且生成該類型的節點返回
  2 TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
  3 {
  4     TiXmlNode* returnNode = 0;
  5 
  6     p = SkipWhiteSpace( p, encoding );
  7     //跳過空格后應該是'<',否則要么出錯要么結束,返回null
  8     if( !p || !*p || *p != '<' )
  9     {
 10         return 0;
 11     }
 12 
 13     p = SkipWhiteSpace( p, encoding );
 14 
 15     if ( !p || !*p )
 16     {
 17         return 0;
 18     }
 19 
 20     
 21     
 22     const char* xmlHeader = { "<?xml" };
 23     const char* commentHeader = { "<!--" };
 24     const char* dtdHeader = { "<!" };
 25     const char* cdataHeader = { "<![CDATA[" };
 26 
 27     //分別判斷接下來是什么
 28     //<?xml 代表是xml文件的declaration
 29     if ( StringEqual( p, xmlHeader, true, encoding ) )
 30     {
 31         #ifdef DEBUG_PARSER
 32             TIXML_LOG( "XML parsing Declaration\n" );
 33         #endif
 34         returnNode = new TiXmlDeclaration();
 35     }
 36     else if ( StringEqual( p, commentHeader, false, encoding ) )
 37     {//<!--代表是注釋
 38         #ifdef DEBUG_PARSER
 39             TIXML_LOG( "XML parsing Comment\n" );
 40         #endif
 41         returnNode = new TiXmlComment();
 42     }
 43     else if ( StringEqual( p, cdataHeader, false, encoding ) )
 44     {//<![CDATA代表CDATA的數據,不過xml並沒有相應去解析,僅僅做為文字處理
 45         #ifdef DEBUG_PARSER
 46             TIXML_LOG( "XML parsing CDATA\n" );
 47         #endif
 48         TiXmlText* text = new TiXmlText( "" );
 49         text->SetCDATA( true );
 50         returnNode = text;
 51     }
 52     else if ( StringEqual( p, dtdHeader, false, encoding ) )
 53     {//<!代表是dtd,不過由於不支持,所以返回為unknown
 54         #ifdef DEBUG_PARSER
 55             TIXML_LOG( "XML parsing Unknown(1)\n" );
 56         #endif
 57         returnNode = new TiXmlUnknown();
 58     }
 59     else if (    IsAlpha( *(p+1), encoding )
 60               || *(p+1) == '_' )
 61     {//如果是字符,則說明為element
 62         #ifdef DEBUG_PARSER
 63             TIXML_LOG( "XML parsing Element\n" );
 64         #endif
 65         returnNode = new TiXmlElement( "" );
 66     }
 67     else
 68     {//否則就是unknown
 69         #ifdef DEBUG_PARSER
 70             TIXML_LOG( "XML parsing Unknown(2)\n" );
 71         #endif
 72         returnNode = new TiXmlUnknown();
 73     }
 74 
 75     if ( returnNode )
 76     {
 77         // Set the parent, so it can report errors
 78         returnNode->parent = this;
 79     }
 80     return returnNode;
 81 }
 82 
 83 //TiXmlDocument的Parse,在LoadFile時被調用
 84 const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
 85 {
 86     ClearError();
 87 
 88     if ( !p || !*p )
 89     {
 90         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
 91         return 0;
 92     }
 93 
 94     location.Clear();
 95     if ( prevData )
 96     {
 97         location.row = prevData->cursor.row;
 98         location.col = prevData->cursor.col;
 99     }
100     else
101     {
102         location.row = 0;
103         location.col = 0;
104     }
105     //構造parsing data,用於記錄數據的位置
106     TiXmlParsingData data( p, TabSize(), location.row, location.col );
107     location = data.Cursor();
108 
109     if ( encoding == TIXML_ENCODING_UNKNOWN )
110     {
111         // 判斷是否是utf8 bom格式
112         const unsigned char* pU = (const unsigned char*)p;
113         if (    *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
114              && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
115              && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
116         {
117             encoding = TIXML_ENCODING_UTF8;
118             useMicrosoftBOM = true;
119         }
120     }
121     
122     //跳過所有的空格符,包括\n\r\t ' '等.直接使用english的方式.在utf8情況下也很正常.
123     p = SkipWhiteSpace( p, encoding );
124     if ( !p )
125     {
126         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
127         return 0;
128     }
129 
130     while ( p && *p )
131     {
132         //利用Identify的方法來判斷是某種元素,並且使用該種元素進行解析接下來的數據.
133         TiXmlNode* node = Identify( p, encoding );
134         if ( node )
135         {
136             p = node->Parse( p, &data, encoding );
137             //將節點鏈接到最后的子節點之后.
138             //LinkEndChild將節點的所有權直接改到父節點.減少一次復制
139             LinkEndChild( node );
140         }
141         else
142         {
143             break;
144         }
145 
146         // Did we get encoding info?
147         if (    encoding == TIXML_ENCODING_UNKNOWN
148              && node->ToDeclaration() )
149         {
150             TiXmlDeclaration* dec = node->ToDeclaration();
151             const char* enc = dec->Encoding();
152             assert( enc );
153 
154             if ( *enc == 0 )
155                 encoding = TIXML_ENCODING_UTF8;
156             else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
157                 encoding = TIXML_ENCODING_UTF8;
158             else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
159                 encoding = TIXML_ENCODING_UTF8;    // incorrect, but be nice
160             else 
161                 encoding = TIXML_ENCODING_LEGACY;
162         }
163 
164         p = SkipWhiteSpace( p, encoding );
165     }
166 
167     // Was this empty?
168     if ( !firstChild ) {
169         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
170         return 0;
171     }
172 
173     return p;
174 }
175 
176 //TiXmlElement::Parse,在TiXmlDocument中,檢測到是element節點后被調用
177 //p代表讀取的文本數據
178 const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
179 {
180     p = SkipWhiteSpace( p, encoding );
181     TiXmlDocument* document = GetDocument();
182 
183     //讀取element時不應該出現結束的情況,返回錯誤
184     if ( !p || !*p )
185     {
186         if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
187         return 0;
188     }
189 
190     if ( data )
191     {
192         //計算目前處理的字符所在的位置
193         //會有一定的性能影響.可以選擇關閉
194         data->Stamp( p, encoding );
195         location = data->Cursor();
196     }
197 
198     //這個應該不會遇到
199     if ( *p != '<' )
200     {
201         if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
202         return 0;
203     }
204 
205     p = SkipWhiteSpace( p+1, encoding );
206 
207     //獲取節點的名字
208     const char* pErr = p;
209 
210     //TiXMlElement的工具函數,讀取tag的name
211     p = ReadName( p, &value, encoding );
212     if ( !p || !*p )
213     {
214         if ( document )    document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
215         return 0;
216     }
217 
218     //構造結尾標識符
219     TIXML_STRING endTag ("</");
220     endTag += value;
221 
222     // 獲取element中的屬性,結尾標識符
223     while ( p && *p )
224     {
225         pErr = p;
226         p = SkipWhiteSpace( p, encoding );
227         if ( !p || !*p )
228         {
229             if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
230             return 0;
231         }
232         if ( *p == '/' )
233         {
234             ++p;
235             // 是空的tag,不具有子節點, <xxx   />
236             if ( *p  != '>' )
237             {
238                 if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );        
239                 return 0;
240             }
241             return (p+1);
242         }
243         else if ( *p == '>' )
244         {
245             // 處理完屬性,下一步處理子節點
246             ++p;
247             //ReadValue會處理<x> </x>之間內的所有數據,包括文字,子節點.處理結束后返回
248             p = ReadValue( p, data, encoding );        
249             if ( !p || !*p ) {
250                 //到結尾了,這不應該發生
251                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
252                 return 0;
253             }
254 
255             if ( StringEqual( p, endTag.c_str(), false, encoding ) )
256             {
257                 p += endTag.length();
258                 p = SkipWhiteSpace( p, encoding );
259                 if ( p && *p && *p == '>' ) {
260                     ++p;
261                     return p;
262                 }
263                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
264                 return 0;
265             }
266             else
267             {
268                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
269                 return 0;
270             }
271         }
272         else
273         {
274             // 是屬性,進行處理
275             //生成一個屬性節點,然后調用該節點parse接下來的數據
276             TiXmlAttribute* attrib = new TiXmlAttribute();
277             if ( !attrib )
278             {
279                 return 0;
280             }
281 
282             attrib->SetDocument( document );
283             pErr = p;
284             p = attrib->Parse( p, data, encoding );
285 
286             if ( !p || !*p )
287             {
288                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
289                 delete attrib;
290                 return 0;
291             }
292 
293             // 重復屬性,直接報錯,返回
294             #ifdef TIXML_USE_STL
295             TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
296             #else
297             TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
298             #endif
299             if ( node )
300             {
301                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
302                 delete attrib;
303                 return 0;
304             }
305 
306             //將該節點加入到attributeset中.
307             attributeSet.Add( attrib );
308         }
309     }
310     return p;
311 }

 

后語:

  關於tinyxml的介紹大致到這里了.本文介紹了tinyxml的整體處理流程以及其實現的一些細節.之前也有讀者提示說tinyxml很慢.而慢的原因有很多,一個是其用了很多多態,而多態是有一定的代價的.另外,其整體實現都是以樹的方式完成的,包括element的屬性是以鏈表的方式實現的,查找等效率都比較低下.

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM