SAX是Simple API for XML的簡寫,是一種解析XML文件的替代方法,不是由W3C官方所提出的標準,是一種事件驅動的XML API,接近於底層,速度較快,但不便於隨機訪問任意節點。 程序員
SAX解析的核心是事件處理機制,具備佔用內存少,效率高等特色。網絡
SAX採用事件機制的方式來解析XML文檔。使用SAX解析器對XML文檔進行解析時,SAX解析器根本不建立任何對象,只是在遇到XML文檔的各類標籤如文檔開始、元素開始、文本、元素結束時觸發對應的事件,並將XML元素的內容封裝成事件傳出去。而程序員則負責提供事件監聽器來監聽這些事件,從而觸發相應的事件處理方法,並經過這些事件處理方法實現對XML文檔的訪問。app
SAX解析事件一共有4種,須要分別設置4種監聽器:ide
A、ContentHandler:監聽XML文檔內容處理事件的監聽器函數
B、DTDHander:監聽DTD處理事件的監聽器this
C、EntityResolver:監聽實體處理事件的監聽器編碼
D、ErrorHandler:監聽解析錯誤的監聽器spa
QT的QtXml模塊中提供了一個基於SAX的XML解析器QXmlSimpleReader類。當解析器解析一個XML的元素時,解析器會依次調用以下事件處理函數:startElement(),characters(),endElement()。能夠在 startElement()中得到元素名(如「title」)和屬性,在characters()中得到元素中的文本(如「Qt」),在endElement()中進行一些結束讀取該元素時想要進行的操做。而全部的這些事件處理函數均可以經過繼承QXmlDefaultHandler類來重寫。xml
QXmlSimpleReader類提供了簡單XML解析器的實現。對象
XML讀取器適合大部分應用程序,可以解析良構XML,但不能解析任何外部實體。
QXmlSimpleReader類最容易的使用模式是建立一個實例,定義一個輸入源,指定讀取器使用的處理器,解析數據。
當讀取器遇到內容中的某種類型或是輸入源中發現錯誤,處理器會採起行動。讀取器必須被告知須要哪種事件類型的處理器。對於大多數應用程序來講,能夠自定義一個繼承於QXmlDefaultHandler類的處理器類,使用自定義的處理器處理錯誤和內容事件。
若是至少連錯誤和內容處理器都沒有設置,解析器將會默認什麼都不作。
處理輸入源最方便的方式是使用帶指定輸入源參數的parse()函數以單通道的方式讀取輸入源。若是一次讀取不能解析整個輸入源(好比XML文件太大或是正在網絡上傳輸),XML文件能夠被解析器分塊讀取。分塊讀取解析能夠經過告知prase()函數以遞增方式工做,隨後調用parseContinue()函數,直到全部數據被解析完成來實現。
實現遞增解析一般的方式是鏈接信號readyRead()到網絡應答的槽函數,而且處理收到的數據。
解析行爲能夠經過使用setFeature()函數和setProperty()函數進行調整。
[virtual] void QXmlSimpleReader::setContentHandler(QXmlContentHandler *handler)
設置內容處理器到handler
[virtual] void QXmlSimpleReader::setErrorHandler(QXmlErrorHandler *handler)
設置錯誤處理器到handler,若是handler爲0,清空錯誤處理器
[virtual] void QXmlSimpleReader::setDTDHandler(QXmlDTDHandler *handler)
[virtual] void QXmlSimpleReader::setDeclHandler(QXmlDeclHandler *handler)
[virtual] void QXmlSimpleReader::setEntityResolver(QXmlEntityResolver *handler)
[virtual] void QXmlSimpleReader::setLexicalHandler(QXmlLexicalHandler *handler)
[virtual] void QXmlSimpleReader::setFeature(const QString &name, bool enable)
[virtual] void QXmlSimpleReader::setProperty(const QString &name, void *value)
[virtual] QXmlErrorHandler *QXmlSimpleReader::errorHandler() const
返回錯誤處理器,若是沒有設置,返回0
[virtual] QXmlContentHandler *QXmlSimpleReader::contentHandler() const
返回內容處理器,若是沒有設置,返回0
[virtual] bool QXmlSimpleReader::hasFeature(const QString &name) const
若是讀取器有名爲name的特性,返回true
QXmlDefaultHandler類提供了全部XML處理器類的實現,集成了特定處理器類的特性,使QXmlReader子類自定義處理器類有了一個便捷的切入點,特別是QXmlSimpleReader類。從基類中繼承的虛函數都會在QXmlDefaultHandler類中重寫。經過繼承QXmlDefaultHandler類,重寫相關虛函數,開發人員可以專一於處理器相關部分的實現。
在解析期間,XML讀取器必須被告知要使用哪種事件的處理器。這就意味着,QXmlDefaultHandler雖然提供了從基類繼承來的函數的默認實現,咱們仍然能夠對特殊的事件使用指定的處理器。
例如,QXmlDefaultHandler繼承了QXmlContentHandler和QXmlErrorHandler,所以經過繼承QXmlDefaultHandler,咱們可使用QXmlContentHandler和QXmlErrorHandler的處理器。
xmlReader.setContentHandler(handler);
xmlReader.setErrorHandler(handler);
因爲讀取器將會通知解析錯誤的處理器,須要重寫QXmlErrorHandler::fatalError()函數,當錯誤發生時須要中止解析。
bool Handler::fatalError (const QXmlParseException & exception)
{
qWarning() << "Fatal error on line" << exception.lineNumber()
<< ", column" << exception.columnNumber() << ':'
<< exception.message();
return false;
}
fatalError()函數返回false會告訴解析器中止解析,。要繼續使用同一個讀取器須要建立一個新的處理器實例,設置使用它的讀取器。
審查從QXmlDefaultHandler類繼承來的某些函數和思考爲何在自定義處理器類中要重寫這些函數是有用的。自定義處理器類爲了準備新內容的處理器一般會重寫QXmlContentHandler::startDocument()函數。經過重寫QXmlContentHandler::startElement(), QXmlContentHandler::endElement(), and QXmlContentHandler::characters()函數,文檔元素和文本會被處理。一旦文檔已經徹底被讀取,須要重寫QXmlContentHandler::endDocument()函數爲了在內容上作某些終結或是確認。
[virtual] bool QXmlDefaultHandler::characters(const QString &ch)
當解析完了字符數據中的垃圾數據時,讀取器會調用本函數
[virtual] bool QXmlDefaultHandler::comment(const QString &ch)
[virtual] bool QXmlDefaultHandler::endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
[virtual] bool QXmlDefaultHandler::error(const QXmlParseException &exception)
[virtual] QString QXmlDefaultHandler::errorString() const
[virtual] bool QXmlDefaultHandler::fatalError(const QXmlParseException &exception)
[virtual] bool QXmlDefaultHandler::processingInstruction(const QString &target, const QString &data)
[virtual] bool QXmlDefaultHandler::startDocument()
[virtual] bool QXmlDefaultHandler::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
[virtual] bool QXmlDefaultHandler::endDocument()
[virtual] bool QXmlDefaultHandler::endEntity(const QString &name)
[virtual] bool QXmlDefaultHandler::endPrefixMapping(const QString &prefix)
[virtual] bool QXmlDefaultHandler::startEntity(const QString &name)
[virtual] bool QXmlDefaultHandler::startPrefixMapping(const QString &prefix, const QString &uri)
void characters(char[] ch,int start,int length)
SAX解析器處理字符數據時觸發該方法
void endDocument():
SAX解析器處理文檔結束時觸發該方法
void endElement(String uri,String localName,String qName):
SAX解析器處理元素結束時觸發該方法
void endPrefixMapping(String prefix)
SAX解析器處理元素裏命名空間屬性(即xmlns:prefix屬性)結束時觸發該方法
void ignorableWhitesapce(char[] ch,int start,int length)
SAX解析器處理元素內容中可忽略的空白時觸發該方法
void skippedEntity(String name)
SAX解析器跳過實體時觸發該方法
void startDocument():
SAX解析器開始處理文檔時觸發該方法
void startElement(String uri,String localName,String qName,Attributes atts):
SAX解析器開始處理元素時觸發該方法
void startPrefixMapping(String prefix,String uri)
SAX解析器開始處理元素裏命名空間屬性(即xmlns:prefix屬性)時觸發該方法
void parse(InputSource input)
解析InputSource輸入源中的XML文檔
void parse(String systemId)
解析系統URI所表明的XML文檔
QT中提供了一個基於SAX的簡單的XML解析器QXmlSimpleReader,QXmlSimpleReader解析器須要QXmlInputSource爲其提供數據,QXmlInputSource會使用相應的編碼來讀取XML文檔的數據。在進行解析以前,還須要使用setContentHandler()來設置事件處理器,使用setErrorHandler()來設置錯誤處理器,使用參數this, 代表使用本類做爲處理器,也就是在解析過程當中出現的各類事件都會使用本類的startElement()等事件處理函數來進行處理,而出現錯誤時會使用本類的fatalError()函數來處理。最後,調用了parse()函數來進行解析,parse()函數會在解析成功時返回true,不然返回false。
創建工程,在工程文件中添加XML模塊支持。
自定義繼承自QXmlDefaultHandler的類,類名爲SAX_XML。重寫QXmlDefaultHandler類的startElement()、endElement()、characters()和fatalError()函數,定義readXML()函數用來讀入XML文件,QListWidget部件用來顯示解析後的XML文檔內容,currentText字符串變量用於暫存字符數據。
SAX_XML類文件以下:
sax_xml.h文件:
#ifndef SAX_XML_H #define SAX_XML_H #include <QXmlDefaultHandler> #include <QListWidget> #include <QString> class SAX_XML : public QXmlDefaultHandler { public: SAX_XML(); ~SAX_XML(); bool readXML(const QString & fileName); protected: bool characters(const QString &ch); bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName); bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts); bool fatalError(const QXmlParseException &exception); private: QListWidget *list; QString currentText; }; #endif // SAX_XML_H
sax_xml.cpp文件:
#include "sax_xml.h" #include <QDebug> SAX_XML::SAX_XML() { list = new QListWidget; list->show(); } bool SAX_XML::readXML(const QString &fileName) { QFile file(fileName); // 讀取文件內容 QXmlInputSource inputSource(&file); // 創建QXmlSimpleReader對象 QXmlSimpleReader reader; // 設置內容處理器 reader.setContentHandler(this); // 設置錯誤處理器 reader.setErrorHandler(this); // 解析文件 return reader.parse(inputSource); } bool SAX_XML::characters(const QString &ch) { currentText = ch; return true; } bool SAX_XML::endElement(const QString &namespaceURI, const QString &localName, const QString &qName) { if (qName == "title" || qName == "author") list->addItem(" " + qName + " : " + currentText); return true; } bool SAX_XML::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts) { if (qName == "library") list->addItem(qName); else if (qName == "book") list->addItem(" " + qName + atts.value("id")); return true; } bool SAX_XML::fatalError(const QXmlParseException &exception) { qDebug() << exception.message(); return false; } SAX_XML::~SAX_XML() { delete list; }
Main.cpp文件:
#include "sax_xml.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); SAX_XML reader; reader.readXML("test.xml"); return a.exec(); }