Qt使用SAX解析xml文件的例子
在开始例子之前,首先了解一下SAX是什么?。
SAX的全称是:simple API for XML,它是解析xml文件的一种方法。与之对应的另一种方法是DOM(Document Object Model)。既然两种方法都能存在,那就说明各有千秋了。SAX是一种边读取边解析的方法,由此带来的好处是它相对于DOM的解析速度更快,缺点是不容易修改xml文件。
Qt对DOM和SAX两种解析方式都支持。这里写个sax的例子试一下。xml内容来自于网络的一个简单例子:
<bookstore> <book category="CHILDREN"> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="WEB"> <title>Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>
文件的结构一目了然,一个bookstore里有两个book,每个book都有category、title、author、year和price几个参数。(在实际开发中像这么小的文件使用DOM模型的方法更合适一些)
步骤:
使用xml的模块要在pro文件中加上 QT += xml
sax需要的几个对象:QXmlSimpleReader、QXmlInputSource、QXmlDefaultHandler。它们的关系可以描述为:reader读取source的内容,并使用handler来解析。所以handler是我们关注的重点,我们从QXmlDefaultHandler中派生一个处理类并重写它的处理函数实现xml文件的解析。
class Handler : public QXmlDefaultHandler { public: Handler(); protected: bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts); bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName); bool characters(const QString &ch); bool error(const QXmlParseException &exception); private: QString m_currentQName; s_Book* m_pBook; QList<s_Book*> m_bookList; };
我们重写了startElement、endElement、characters和error几个接口分别表示遇到元素开始、元素结束、字符和错误。 s_Book是定义的book的结构体:
struct s_Book { s_Book() {} QString _category; QString _title; QString _author; int _year; float _price; };
接着看看在四个接口中是如何来解析文件的:
bool Handler::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts) { if(qName == "bookstore"){ } else if(qName == "book"){ m_pBook = new s_Book; m_pBook->_category = atts.value("category"); } else{ m_currentQName = qName; } return true; } bool Handler::endElement(const QString &namespaceURI, const QString &localName, const QString &qName) { m_currentQName = ""; if(qName == "book"){ m_bookList.append(m_pBook); }else if(qName == "bookstore"){ for(int i = 0; i < m_bookList.count(); ++i){ s_Book* book = m_bookList.at(i); QString ret("["); ret.append(book->_title + " : "); ret.append(book->_category + " "); ret.append(book->_author + " "); ret.append(QString::number(book->_year) + " "); ret.append(QString::number(book->_price) + "]"); qDebug()<<ret; } } return true; } bool Handler::characters(const QString &ch) { if(m_currentQName == "title"){ m_pBook->_title = ch; } else if(m_currentQName == "author"){ m_pBook->_author = ch; }else if(m_currentQName == "year"){ m_pBook->_year = ch.toInt(); }else if(m_currentQName == "price"){ m_pBook->_price = ch.toFloat(); } return true; } bool Handler::error(const QXmlParseException &exception) { return false; }
当遇到book的开始元素时表示开始解析一个book的内容,此时创建一个book对象用于存储数据,当遇到book元素结束时表示当前解析的book结束了,把解析完的book对象中加入到列表中。当解析到bookstore的元素结束时表示所有内容都解析完成,此时把所有book的打印出来。
从文档上可以看出除了category是属于元素的属性以外,其他内容都属于字符,都是通过characters接口解析出来的。特别注意的一点是这几个接口返回为false时就会停止解析。
3.有了reader、source和handler就可以开始解析xml文件了。
QFile f(":/test.xml"); QXmlInputSource source(&f); QXmlSimpleReader reader; Handler hander; reader.setContentHandler(&hander); reader.setErrorHandler(&hander); reader.parse(source);
reader设置好handler后调用parse解析source整个过程就结束了,就是这么简单。
4.输出结果:
"[Harry Potter : CHILDREN J K. Rowling 2005 29.99]"
"[Learning XML : WEB Erik T. Ray 2003 39.95]"