继续,刚才发表时出错,打开一看是别的人文章了!又白写了,晕……刚才的思路没了,重新来过吧。
书接上回,这篇介绍那个MContentHandler的实现,这是SAX解析方法的核心所在。
先看看我要解析的XML文件如下所示,其实很简单,因为它除了Element和Attribute以外没有其它东西了。
<?
xmlversion="1.0"encoding="utf-8"
?>
<
channels
>
<
channel
id
="10"
title
="时政"
>
<
content
id
="1001"
title
="广东牛奶中毒事件污染源调查结果1周后公布"
/>
<
content
id
="1002"
title
="河南淅川公安局因儿童被拐案设'局耻日'"
/>
<
content
id
="1003"
title
="深圳大学135名师生感染病毒引发腹泻"
/>
</
channel
>
<
channel
id
="11"
title
="国际"
>
<
content
id
="1101"
title
="巴以将于4月7日恢复领导人级和谈"
/>
<
content
id
="1102"
title
="古巴解除长期禁令允许国民入住涉外酒店"
/>
<
content
id
="1103"
title
="联合国决定继续对刚果(金)实行武器禁运"
/>
<
content
id
="1104"
title
="俄拒绝接受美国进攻性战略武器问题建议"
/>
</
channel
>
<
channel
id
="12"
title
="财经"
>
<
content
id
="1201"
title
="大飞机公司拟定名中国商用飞机有限公司"
/>
<
content
id
="1202"
title
="大部制新部委定编制方案6月底前上报"
/>
</
channel
>
</
channels
>
我们的解析处理器的声明如下:
#include
<
xmlcontenthandler.h
>
#include
<
xmldocumentparameters.h
>

using
namespace
Xml;

class
TNewsChannel

...
{
public:
TIntid;
HBufC16*title;
}
;

class
TNewsContent

...
{
public:
TIntid;
TIntpid;
HBufC16*title;
}
;


class
CChannelXmlHandler:
public
MContentHandler
...
{
public:
//Constructorsanddestructor
~CChannelXmlHandler();
staticCChannelXmlHandler*NewL();
staticCChannelXmlHandler*NewLC();

RArray<TNewsChannel>*GetChannels();
RArray<TNewsContent>*GetContents();
TIntGetContent(TIntpid,TIntindex);
TIntContentCount(TIntpid);

private:

CChannelXmlHandler();
voidConstructL();

private://fromMContentHandler

voidOnStartDocumentL(constRDocumentParameters&aDocParam,
TIntaErrorCode);

voidOnEndDocumentL(TIntaErrorCode);

voidOnStartElementL(constRTagInfo&aElement,
constRAttributeArray&aAttributes,TIntaErrorCode);

voidOnEndElementL(constRTagInfo&aElement,TIntaErrorCode);

voidOnContentL(constTDesC8&aBytes,TIntaErrorCode);

//......

private:
TIntiCurPID;
RArray<TNewsChannel>iChannels;
RArray<TNewsContent>iContents;

}
;
大多数是MContentHandler所声明的方法,这就是SAX事件解析模式的关键了,我们只需要在这些方法中做相应的处理即可。
除此之外,iChannels和iContents是我们定义了用来保存解析结果的成员,它的类型是RArray,关于RArray可以参考我的别一篇笔记: http://blog.youkuaiyun.com/sharetop/archive/2008/03/21/2203450.aspx
因为我们的XML比较简单,所以在CPP中只要处理OnStartElementL就可以了:
void
CChannelXmlHandler::OnStartElementL(
const
Xml::RTagInfo
&
aElement,
const
Xml::RAttributeArray
&
aAttributes,TIntaErrorCode)

...
{

if(aElement.LocalName().DesC().Compare(KChannelName)==0)...{
TNewsChannelchn;

for(TInti=0;i<aAttributes.Count();i++)...{

if(aAttributes[i].Attribute().LocalName().DesC().Compare(KTitleName)==0)...{
chn.title=CnvUtfConverter::ConvertToUnicodeFromUtf8L(aAttributes[i].Value().DesC());
}

elseif(aAttributes[i].Attribute().LocalName().DesC().Compare(KIdName)==0)...{
TLex8lex;
lex.Assign(aAttributes[i].Value().DesC());
lex.Val(chn.id);
}
}
iChannels.Append(chn);
iCurPID=chn.id;
}

elseif(aElement.LocalName().DesC().Compare(KContentName)==0)...{
TNewsContentcnt;
cnt.pid=iCurPID;

for(TInti=0;i<aAttributes.Count();i++)...{

if(aAttributes[i].Attribute().LocalName().DesC().Compare(KIdName)==0)...{
TLex8lex;
lex.Assign(aAttributes[i].Value().DesC());
lex.Val(cnt.id);
}

elseif(aAttributes[i].Attribute().LocalName().DesC().Compare(KTitleName)==0)...{
cnt.title=CnvUtfConverter::ConvertToUnicodeFromUtf8L(aAttributes[i].Value().DesC());
}
}
iContents.Append(cnt);
}
}
这个回调会在解析器遇到元素头时进入,然后我们就可以根据传入的参数取到当前元素的信息,如元素名称、属性值等,将它们保存在我们定义的数据成员中以备将来使用即可。
在使用这个解析器的地方,比如我们的AppView负责解析XML文件,那它应该包含一个MContentHandler的成员,并且它实现接口MXMLHandlerObserver。
于是,这样启动解析过程:
iChannelHandler
=
CChannelXmlHandler::NewL();
iXmlParser
=
CXMLActiveParser::NewL(
*
this
,
*
iChannelHandler);
iXmlParser
->
StartL(KChannelXMLFile);
然后在它的OnParseCompleted方法中去iChannelHandler中取出解析结果,展示出来或者随便怎么用了。
书接上回,这篇介绍那个MContentHandler的实现,这是SAX解析方法的核心所在。
先看看我要解析的XML文件如下所示,其实很简单,因为它除了Element和Attribute以外没有其它东西了。
<?
xmlversion="1.0"encoding="utf-8"
?>
<
channels
>
<
channel
id
="10"
title
="时政"
>
<
content
id
="1001"
title
="广东牛奶中毒事件污染源调查结果1周后公布"
/>
<
content
id
="1002"
title
="河南淅川公安局因儿童被拐案设'局耻日'"
/>
<
content
id
="1003"
title
="深圳大学135名师生感染病毒引发腹泻"
/>
</
channel
>
<
channel
id
="11"
title
="国际"
>
<
content
id
="1101"
title
="巴以将于4月7日恢复领导人级和谈"
/>
<
content
id
="1102"
title
="古巴解除长期禁令允许国民入住涉外酒店"
/>
<
content
id
="1103"
title
="联合国决定继续对刚果(金)实行武器禁运"
/>
<
content
id
="1104"
title
="俄拒绝接受美国进攻性战略武器问题建议"
/>
</
channel
>
<
channel
id
="12"
title
="财经"
>
<
content
id
="1201"
title
="大飞机公司拟定名中国商用飞机有限公司"
/>
<
content
id
="1202"
title
="大部制新部委定编制方案6月底前上报"
/>
</
channel
>
</
channels
>
我们的解析处理器的声明如下:
#include
<
xmlcontenthandler.h
>
#include
<
xmldocumentparameters.h
>

using
namespace
Xml;
class
TNewsChannel
...
{
public:
TIntid;
HBufC16*title;
}
;
class
TNewsContent
...
{
public:
TIntid;
TIntpid;
HBufC16*title;
}
;

class
CChannelXmlHandler:
public
MContentHandler
...
{
public:
//Constructorsanddestructor
~CChannelXmlHandler();
staticCChannelXmlHandler*NewL();
staticCChannelXmlHandler*NewLC();
RArray<TNewsChannel>*GetChannels();
RArray<TNewsContent>*GetContents();
TIntGetContent(TIntpid,TIntindex);
TIntContentCount(TIntpid);
private:
CChannelXmlHandler();
voidConstructL();
private://fromMContentHandler
voidOnStartDocumentL(constRDocumentParameters&aDocParam,
TIntaErrorCode);
voidOnEndDocumentL(TIntaErrorCode);
voidOnStartElementL(constRTagInfo&aElement,
constRAttributeArray&aAttributes,TIntaErrorCode);
voidOnEndElementL(constRTagInfo&aElement,TIntaErrorCode);
voidOnContentL(constTDesC8&aBytes,TIntaErrorCode);
//......
private:
TIntiCurPID;
RArray<TNewsChannel>iChannels;
RArray<TNewsContent>iContents;
}
;
大多数是MContentHandler所声明的方法,这就是SAX事件解析模式的关键了,我们只需要在这些方法中做相应的处理即可。
除此之外,iChannels和iContents是我们定义了用来保存解析结果的成员,它的类型是RArray,关于RArray可以参考我的别一篇笔记: http://blog.youkuaiyun.com/sharetop/archive/2008/03/21/2203450.aspx
因为我们的XML比较简单,所以在CPP中只要处理OnStartElementL就可以了:
void
CChannelXmlHandler::OnStartElementL(
const
Xml::RTagInfo
&
aElement,
const
Xml::RAttributeArray
&
aAttributes,TIntaErrorCode)
...
{
if(aElement.LocalName().DesC().Compare(KChannelName)==0)...{
TNewsChannelchn;
for(TInti=0;i<aAttributes.Count();i++)...{
if(aAttributes[i].Attribute().LocalName().DesC().Compare(KTitleName)==0)...{
chn.title=CnvUtfConverter::ConvertToUnicodeFromUtf8L(aAttributes[i].Value().DesC());
}
elseif(aAttributes[i].Attribute().LocalName().DesC().Compare(KIdName)==0)...{
TLex8lex;
lex.Assign(aAttributes[i].Value().DesC());
lex.Val(chn.id);
}
}
iChannels.Append(chn);
iCurPID=chn.id;
}
elseif(aElement.LocalName().DesC().Compare(KContentName)==0)...{
TNewsContentcnt;
cnt.pid=iCurPID;
for(TInti=0;i<aAttributes.Count();i++)...{
if(aAttributes[i].Attribute().LocalName().DesC().Compare(KIdName)==0)...{
TLex8lex;
lex.Assign(aAttributes[i].Value().DesC());
lex.Val(cnt.id);
}
elseif(aAttributes[i].Attribute().LocalName().DesC().Compare(KTitleName)==0)...{
cnt.title=CnvUtfConverter::ConvertToUnicodeFromUtf8L(aAttributes[i].Value().DesC());
}
}
iContents.Append(cnt);
}
}
这个回调会在解析器遇到元素头时进入,然后我们就可以根据传入的参数取到当前元素的信息,如元素名称、属性值等,将它们保存在我们定义的数据成员中以备将来使用即可。
在使用这个解析器的地方,比如我们的AppView负责解析XML文件,那它应该包含一个MContentHandler的成员,并且它实现接口MXMLHandlerObserver。
于是,这样启动解析过程:
iChannelHandler
=
CChannelXmlHandler::NewL();
iXmlParser
=
CXMLActiveParser::NewL(
*
this
,
*
iChannelHandler);
iXmlParser
->
StartL(KChannelXMLFile);
然后在它的OnParseCompleted方法中去iChannelHandler中取出解析结果,展示出来或者随便怎么用了。
本文介绍了一个具体的SAX解析XML的例子,展示了如何通过C++实现一个解析器来处理简单的新闻频道和内容数据。
448

被折叠的 条评论
为什么被折叠?



