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);
}