Symbian學(xué)習(xí)筆記(16)
先看看我要解析的XML文件如下所示,其實很簡單,因為它除了Element和Attribute以外沒有其它東西了。
<channels>
<channel id="10" title="時政" >
<content id="1001" title="廣東牛奶中毒事件污染源調(diào)查結(jié)果1周后公布"/>
<content id="1002" title="河南淅川公安局因兒童被拐案設(shè)'局恥日'"/>
<content id="1003" title="深圳大學(xué)135名師生感染病毒引發(fā)腹瀉"/>
</channel>
<channel id="11" title="國際">
<content id="1101" title="巴以將于4月7日恢復(fù)領(lǐng)導(dǎo)人級和談"/>
<content id="1102" title="古巴解除長期禁令允許國民入住涉外酒店"/>
<content id="1103" title="聯(lián)合國決定繼續(xù)對剛果(金)實行武器禁運"/>
<content id="1104" title="俄拒絕接受美國進(jìn)攻性戰(zhàn)略武器問題建議"/>
</channel>
<channel id="12" title="財經(jīng)">
<content id="1201" title="大飛機公司擬定名中國商用飛機有限公司"/>
<content id="1202" title="大部制新部委定編制方案6月底前上報"/>
</channel>
</channels>
我們的解析處理器的聲明如下:
#include <xmldocumentparameters.h>
using namespace Xml;
class TNewsChannel
...{
public:
TInt id;
HBufC16 * title;
};
class TNewsContent
...{
public:
TInt id;
TInt pid;
HBufC16 * title;
};
class CChannelXmlHandler : public MContentHandler ...{
public:
// Constructors and destructor
~CChannelXmlHandler();
static CChannelXmlHandler* NewL();
static CChannelXmlHandler* NewLC();
RArray<TNewsChannel>* GetChannels();
RArray<TNewsContent>* GetContents();
TInt GetContent(TInt pid,TInt index);
TInt ContentCount(TInt pid);
private:
CChannelXmlHandler();
void ConstructL();
private: // from MContentHandler
void OnStartDocumentL( const RDocumentParameters &aDocParam,
TInt aErrorCode );
void OnEndDocumentL( TInt aErrorCode );
void OnStartElementL( const RTagInfo &aElement,
const RAttributeArray &aAttributes, TInt aErrorCode );
void OnEndElementL( const RTagInfo &aElement, TInt aErrorCode );
void OnContentL( const TDesC8 &aBytes, TInt aErrorCode );
// ... ...
private:
TInt iCurPID;
RArray<TNewsChannel> iChannels;
RArray<TNewsContent> iContents;
};
大多數(shù)是MContentHandler所聲明的方法,這就是SAX事件解析模式的關(guān)鍵了,我們只需要在這些方法中做相應(yīng)的處理即可。
除此之外,iChannels和iContents是我們定義了用來保存解析結(jié)果的成員,它的類型是RArray,關(guān)于RArray可以參考我的別一篇筆記:http://blog.csdn.net/sharetop/archive/2008/03/21/2203450.aspx
因為我們的XML比較簡單,所以在CPP中只要處理OnStartElementL就可以了:
這個回調(diào)會在解析器遇到元素頭時進(jìn)入,然后我們就可以根據(jù)傳入的參數(shù)取到當(dāng)前元素的信息,如元素名稱、屬性值等,將它們保存在我們定義的數(shù)據(jù)成員中以備將來使用即可。
在使用這個解析器的地方,比如我們的AppView負(fù)責(zé)解析XML文件,那它應(yīng)該包含一個MContentHandler的成員,并且它實現(xiàn)接口MXMLHandlerObserver。
于是,這樣啟動解析過程:
iXmlParser=CXMLActiveParser::NewL(*this,*iChannelHandler);
iXmlParser->StartL(KChannelXMLFile);
然后在它的OnParseCompleted方法中去iChannelHandler中取出解析結(jié)果,展示出來或者隨便怎么用了。
const Xml::RAttributeArray &aAttributes, TInt aErrorCode )
...{
if(aElement.LocalName().DesC().Compare(KChannelName)==0)...{
TNewsChannel chn;
for(TInt i=0;i<aAttributes.Count();i++)...{
if(aAttributes.Attribute().LocalName().DesC().Compare(KTitleName)==0)...{
chn.title=CnvUtfConverter::ConvertToUnicodeFromUtf8L(aAttributes.Value().DesC());
}
else if(aAttributes.Attribute().LocalName().DesC().Compare(KIdName)==0)...{
TLex8 lex;
lex.Assign(aAttributes.Value().DesC());
lex.Val(chn.id);
}
}
iChannels.Append(chn);
iCurPID=chn.id;
}
else if(aElement.LocalName().DesC().Compare(KContentName)==0)...{
TNewsContent cnt;
cnt.pid=iCurPID;
for(TInt i=0;i<aAttributes.Count();i++)...{
if(aAttributes.Attribute().LocalName().DesC().Compare(KIdName)==0)...{
TLex8 lex;
lex.Assign(aAttributes.Value().DesC());
lex.Val(cnt.id);
}
else if(aAttributes.Attribute().LocalName().DesC().Compare(KTitleName)==0)...{
cnt.title=CnvUtfConverter::ConvertToUnicodeFromUtf8L(aAttributes.Value().DesC());
}
}
iContents.Append(cnt);
}
【編輯推薦】