CEGUI中资源文件加载,用到了XML文件解析,内置了几种解析接口,
这里分析一种:ExpatParser
相关类Attribute、Handler、Parser头文件,其中Serializer序列化是给CEGUILayoutEditor用的,使得layout资源文件能以XML文件格式保存。
大致流程为:
1、创建 2、设置 3 解析
处理接口(XMLHandler)有三个主要的函数。
//当一个元素开始的时候会调用
virtual void elementStart(const String& element, const XMLAttributes& attributes);
//当一个元素结束的时候会介绍
virtual void elementEnd(const String& element);
//当一个元素有文本元素的时候会调用,CEGUI中基本没有使用
virtual void text(const String& text);
什么是元素呢?前文已经讲过。这里在详细介绍一下,读者参看下面的代码。
<这是一个元素 属性1="属性值1" 属性2="属性值2">
这是元素对应的文本
</这是一个元素>
当遇到"<这是一个元素"时解析器会调用elementStart函数,当遇到"</这是一个元素>"时解析器会调用elementEnd。需要注意的是元素的结束亦可以这样定义,在<这是一个元素/>。文本信息在开始和结束之间。当遇到文本信息时解析器text函数。XMLAttributes类包含了这个元素对应的属性(在这个例子里面它包含了两个属性和值对)。
那如何加载并处理一个文件呢?首先需要建立一个处理这个文件的处理类,这个类必须派生自XMLHandler接口。然后在加载文件的时候先声明一个处理类的实例,然后调用XML解析模块的主处理函数,就可以处理一类文件了。
部分主要代码:
void ExpatParser::parseXMLFile(XMLHandler& handler, const String& filename, const String& /*schemaName*/, const String& resourceGroup)
{
// All stuff goes here
// 创建一个XML分析器
XML_Parser parser = XML_ParserCreate(0); // Create a parser
if (! parser)
{
throw GenericException("ExpatParser::parseXMLFile - Unable to create a new Expat Parser");
}
//这一部分里的函数从解析器得到状态的信息或者为了设定解析器任意选择能灵活地被使用。
XML_SetUserData(parser, (void*)&handler); // Initialise user data
// 设置每个XML元素出现和结束的处理函数。这里设置start为元素开始处理函数,end元素结束处理函数
XML_SetElementHandler(parser, startElement, endElement); // Register callback for elements
// 为文本准备处理函数
XML_SetCharacterDataHandler(parser, characterData); // Register callback for character data
// Aquire resource using CEGUI ResourceProvider
// 使用CEGUI ResourceProvider获得解析的资源
CEGUI::RawDataContainer rawXMLData;
CEGUI::System::getSingleton().getResourceProvider()->loadRawDataContainer(filename, rawXMLData, resourceGroup);
// Parse the data (note that the last true parameter tels Expat that this is the last chunk of the document
// XML_Parser解析XML文档,把一充满着文件的缓冲区传给解析器
if ( ! XML_Parse(parser, reinterpret_cast<const char*>(rawXMLData.getDataPtr()), rawXMLData.getSize(), true))
{
System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);
String exception (String((const utf8*)"ExpatParser::parseXMLFile - XML Parsing error '") +
String((const utf8*)XML_ErrorString(XML_GetErrorCode(parser))) +
String((const utf8*)"' at line ") +
PropertyHelper::uintToString(XML_GetCurrentLineNumber(parser)));
// (We know it is a valid pointer, otherwise an exception would have been thrown above.)
XML_ParserFree(parser);
throw GenericException(exception);
}
// Release resource
CEGUI::System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);
// (We know it is a valid pointer, otherwise an exception would have been thrown above.)
XML_ParserFree(parser);
}
元素开始处理函数
void ExpatParser::startElement(void* data, const char* element, const char** attr)
{
XMLHandler* handler = static_cast<XMLHandler*>(data);
XMLAttributes attrs;
for(size_t i = 0 ; attr[i] ; i += 2)
attrs.add((const utf8*)attr[i], (const utf8*)attr[i+1]);
handler->elementStart((const utf8*)element, attrs);
}
元素结束处理函数
void ExpatParser::endElement(void* data, const char* element)
{
XMLHandler* handler = static_cast<XMLHandler*>(data);
handler->elementEnd((const utf8*)element);
}
文本处理函数
void ExpatParser::characterData(void *data, const char *text, int len)
{
XMLHandler* handler = static_cast<XMLHandler*>(data);
String str((const utf8*)text, static_cast<String::size_type>(len));
handler->text(str);
}