static
局部变量很可能会中断处理。还记得吗
局部变量在函数调用之间保持其值。一次
streamFile()
退出,然后再次调用
静止的
变量仍将保留其以前的值,不会重置回其原始值。你必须把他们改成你组织的成员
CXMLManager
流文件()
每次调用时都可以重置它们。
我不建议使用一个函数来处理您需要解析的每个可能的节点。我将把reading分解为不同的函数,这些函数在XML文档的每个级别上都有自己的职责,如下所示:
void CXMLManager::readFeed(xmlTextReaderPtr reader)
{
if (xmlTextReaderIsEmptyElement(reader))
return;
int depth = xmlTextReaderNodeDepth(reader);
int ret;
while ((ret = xmlTextReaderRead(reader)) == 1)
{
switch (xmlTextReaderNodeType(reader))
{
case XML_READER_TYPE_ELEMENT:
{
if (xmlStrEqual(xmlTextReaderConstLocalName(reader), BAD_CAST "entry"))
{
CFeed entry;
readFeedEntry(reader, entry);
m_feedBuffer.push_back(entry);
}
break;
}
case XML_READER_TYPE_END_ELEMENT:
{
if ((xmlTextReaderNodeDepth(reader) == depth)
)
{
return;
}
break;
}
}
}
if (ret == -1)
throw CFeedreaderException("FEEDREADER: Failed to read XML.", ...);
}
void CXMLManager::readFeedEntry(xmlTextReaderPtr reader, CFeed &entry)
{
if (xmlTextReaderIsEmptyElement(reader))
return;
int depth = xmlTextReaderNodeDepth(reader);
int ret;
while ((ret = xmlTextReaderRead(reader)) == 1)
{
switch (xmlTextReaderNodeType(reader))
{
case XML_READER_TYPE_ELEMENT:
{
const xmlChar *name = xmlTextReaderConstLocalName(reader);
if (xmlStrEqual(name, BAD_CAST "title"))
{
readText(reader, entry.m_title);
std::cout << "Title: " << entry.m_title << std::endl;
}
break;
}
case XML_READER_TYPE_END_ELEMENT:
{
if ((xmlTextReaderNodeDepth(reader) == depth)
)
{
return;
}
break;
}
}
}
if (ret == -1)
throw CFeedreaderException("FEEDREADER: Failed to read XML.", ...);
}
void CXMLManager::readText(xmlTextReaderPtr reader, std::string &text)
{
text.clear();
if (xmlTextReaderIsEmptyElement(reader))
return;
int depth = xmlTextReaderNodeDepth(reader);
int ret;
while ((ret = xmlTextReaderRead(reader)) == 1)
{
switch (xmlTextReaderNodeType(reader))
{
case XML_READER_TYPE_TEXT:
{
const xmlChar *value = xmlTextReaderConstValue(reader);
text += reinterpret_cast<const char*>(value);
break;
}
case XML_READER_TYPE_END_ELEMENT:
{
if ((xmlTextReaderNodeDepth(reader) == depth)
)
{
return;
}
break;
}
}
}
if (ret == -1)
throw CFeedreaderException("FEEDREADER: Failed to read XML.", ...);
}
void CXMLManager::streamFile(const char *data, size_t size)
{
xmlTextReaderPtr reader = xmlReaderForMemory(data, size, NULL, NULL,
XML_PARSE_DTDATTR |
XML_PARSE_NOENT);
if (!reader)
throw CFeedreaderException("FEEDREADER: Failed to parse XML.", E_WRONG_XML);
std::unique_ptr<xmlTextReader, decltype(xmlFreeTextReader)> reader_deleter(reader, xmlFreeTextReader);
int ret;
while ((ret = xmlTextReaderRead(reader)) == 1)
{
if ((xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
&& xmlStrEqual(xmlTextReaderConstLocalName(reader), BAD_CAST "feed"))
{
readFeed(reader);
}
}
if (ret == -1)
throw CFeedreaderException("FEEDREADER: Failed to read XML.", ...);
}
或者,我建议完全去掉所有的helper函数,只在
流文件()
它本身,使用本地状态机在
reader
例如:
void CXMLManager::streamFile(const char *data, size_t size)
{
xmlTextReaderPtr reader = xmlReaderForMemory(data, size, NULL, NULL,
XML_PARSE_DTDATTR |
XML_PARSE_NOENT);
if (!reader)
throw CFeedreaderException("FEEDREADER: Failed to parse XML.", E_WRONG_XML);
std::unique_ptr<xmlTextReader, decltype(xmlFreeTextReader)> reader_deleter(reader, xmlFreeTextReader);
std::string name, title, updated, author, link, text;
int feedDepth = -1;
int entryDepth = -1;
int textDepth = -1;
int ret;
while ((ret = xmlTextReaderRead(reader)) == 1)
{
switch (xmlTextReaderNodeType(reader))
{
case XML_READER_TYPE_ELEMENT:
{
if (textDepth != -1)
{
break;
}
const xmlChar *name = xmlTextReaderConstLocalName(reader);
if (feedDepth == -1)
{
if (xmlStrEqual(name, BAD_CAST "feed"))
{
feedDepth == xmlTextReaderNodeDepth(reader);
}
}
else if (entryDepth == -1)
{
if (xmlStrEqual(name, BAD_CAST "entry"))
{
name = title = updated = author = link = text = "";
if (xmlTextReaderIsEmptyElement(reader))
m_feedBuffer.push_back( CFeed { name, title, updated, author, link } );
else
entryDepth == xmlTextReaderNodeDepth(reader);
}
}
else if (xmlStrEqual(name, BAD_CAST "title"))
{
text.clear();
if (!xmlTextReaderIsEmptyElement(reader))
textDepth = xmlTextReaderNodeDepth(reader);
else
textDepth = -1;
}
break;
}
case XML_READER_TYPE_TEXT:
{
if (textDepth != -1)
{
const xmlChar *value = xmlTextReeaderConstValue(reader);
text += reinterpret_cast<const char*>(value);
}
break;
}
case XML_READER_TYPE_END_ELEMENT:
{
const xmlChar *name = xmlTextReaderConstLocalName(reader);
if (textDepth != -1)
{
if ((xmlTextReaderNodeDepth(reader) == textDepth)
)
{
textDepth = -1;
title = text;
text.clear();
std::cout << "Title: " << title << std::endl;
}
}
else if (entryDepth != -1)
{
if ((xmlTextReaderNodeDepth(reader) == entryDepth)
)
{
entryDepth = -1;
m_feedBuffer.push_back( CFeed { name, title, updated, author, link } );
}
}
else if (feedDepth != -1)
{
if ((xmlTextReaderNodeDepth(reader) == feedDepth)
)
{
feedDepth = -1;
}
}
break;
}
}
}
if (ret == -1)
throw CFeedreaderException("FEEDREADER: Failed to read XML.", ...);
}