(四) - 分析 QXmlStream.h 文件框架 - TokenType - QXmlStreamReader

STEP1、QT源码闭源,只开放.h接口供调用 

以 - xml/ # XML相关实现(QXmlStreamReader等) 来做分析

STEP2、QXmlStream 模块中的类归纳 - 九大类 , 当前只关注 QXmlStreamReader   和  QXmlStreamAttribute 

Q_CORE_EXPORT QXmlStreamStringRef 
Q_CORE_EXPORT QXmlStreamAttribute 
Q_CORE_EXPORT QXmlStreamAttributes : public QVector<QXmlStreamAttribute>
Q_CORE_EXPORT QXmlStreamNamespaceDeclaration 
Q_CORE_EXPORT QXmlStreamNotationDeclaration 
Q_CORE_EXPORT QXmlStreamEntityDeclaration 
Q_CORE_EXPORT QXmlStreamEntityResolver
Q_CORE_EXPORT QXmlStreamReader 
Q_CORE_EXPORT QXmlStreamWrite

 

 

STEP3、QXmlStreamReader 的应用场景 : 读取 配置文件 举例子说明

此函数从给定的 QIODevice 读取 XML 数据,查找所有的 <interface> 元素,并提取它们的 name 属性和内容(IP 地址)

void parseNetworkConfig(QIODevice *device) {
    QXmlStreamReader reader(device);
    while (!reader.atEnd()) {
        if (reader.readNextStartElement()) {  // 移动到下一个开始元素(如果有)
            if (reader.name() == "interface") {
                QString name = reader.attributes().value("name").toString();
                QString ip = reader.readElementText();
                qDebug() << "Interface:" << name << "IP:" << ip;
            }
        }
    }
}

<config>
    <interface name="eth0">192.168.1.1</interface>
    <interface name="wlan0">192.168.1.100</interface>
</config>

  

STEP4、分析 QXmlStreamReader 类 

#ifndef QT_NO_XMLSTREAMREADER
class Q_CORE_EXPORT QXmlStreamReader {
    
	QDOC_PROPERTY(bool namespaceProcessing READ namespaceProcessing WRITE setNamespaceProcessing)
	
public:
    enum TokenType {
        NoToken = 0,
        Invalid,
        StartDocument,
        EndDocument,
        StartElement,
        EndElement,
        Characters,
        Comment,
        DTD,
        EntityReference,
        ProcessingInstruction
    };

    // 数据输入与初始化 : 多源支持:通过构造函数或 setDevice() 支持从 QIODevice、QByteArray、QString 等读取数据
    QXmlStreamReader();
    explicit QXmlStreamReader(QIODevice *device);
    explicit QXmlStreamReader(const QByteArray &data);
    explicit QXmlStreamReader(const QString &data);
    explicit QXmlStreamReader(const char * data);
    ~QXmlStreamReader();

    // 增量解析:addData() 方法允许动态追加数据,适用于网络流或实时数据
    void setDevice(QIODevice *device);
    QIODevice *device() const;
    void addData(const QByteArray &data);
    void addData(const QString &data);
    void addData(const char *data);
    void clear();


    // 状态查询
    bool atEnd() const;                // 判断是否到达文档末尾 
    TokenType tokenType() const;       // 返回当前解析位置的标记类型
    QString tokenString() const;       // 返回当前标记的文本内容
    
	// 事件驱动
	TokenType readNext();              // 移动到下一个标记并返回其类型 ,  readNext 是方法名,而不是枚举值, 返回类型:TokenType 枚举
    bool readNextStartElement();       // 跳过无关标记,直到遇到下一个开始标签
    void skipCurrentElement();         // 跳过当前元素的全部内容(包括子元素)


    void setNamespaceProcessing(bool);
    bool namespaceProcessing() const;

    // 这些内联函数用于判断当前解析位置的标记类型,分别对应文档开始、文档结束、元素开始、元素结束和文本内容。
	// 基本类型判断函数
    inline bool isStartDocument() const { return tokenType() == StartDocument; }
    inline bool isEndDocument() const { return tokenType() == EndDocument; }
    inline bool isStartElement() const { return tokenType() == StartElement; }
    inline bool isEndElement() const { return tokenType() == EndElement; }
    inline bool isCharacters() const { return tokenType() == Characters; }
	// 特殊类型判断函数
    bool isWhitespace() const;
    bool isCDATA() const;
    inline bool isComment() const { return tokenType() == Comment; }
    inline bool isDTD() const { return tokenType() == DTD; }
    inline bool isEntityReference() const { return tokenType() == EntityReference; }
    inline bool isProcessingInstruction() const { return tokenType() == ProcessingInstruction; }





    bool isStandaloneDocument() const;
    QStringRef documentVersion() const;
    QStringRef documentEncoding() const;
	
	
    qint64 lineNumber() const;
    qint64 columnNumber() const;
    qint64 characterOffset() const;
	
	

    QXmlStreamAttributes attributes() const;

    enum ReadElementTextBehaviour {
        ErrorOnUnexpectedElement,
        IncludeChildElements,
        SkipChildElements
    };
    QString readElementText(ReadElementTextBehaviour behaviour = ErrorOnUnexpectedElement);

    QStringRef name() const;
    QStringRef namespaceUri() const;
    QStringRef qualifiedName() const;
    QStringRef prefix() const;

    QStringRef processingInstructionTarget() const;
    QStringRef processingInstructionData() const;

    QStringRef text() const;

    QXmlStreamNamespaceDeclarations namespaceDeclarations() const;
    void addExtraNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaraction);
    void addExtraNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &extraNamespaceDeclaractions);
    QXmlStreamNotationDeclarations notationDeclarations() const;
    QXmlStreamEntityDeclarations entityDeclarations() const;
    QStringRef dtdName() const;
    QStringRef dtdPublicId() const;
    QStringRef dtdSystemId() const;


    enum Error {
        NoError,
        UnexpectedElementError,
        CustomError,
        NotWellFormedError,
        PrematureEndOfDocumentError
    };
    void raiseError(const QString& message = QString());
    QString errorString() const;
    Error error() const;

    inline bool hasError() const
    {
        return error() != NoError;
    }

    void setEntityResolver(QXmlStreamEntityResolver *resolver);
    QXmlStreamEntityResolver *entityResolver() const;

private:
    Q_DISABLE_COPY(QXmlStreamReader)
    Q_DECLARE_PRIVATE(QXmlStreamReader)
    QScopedPointer<QXmlStreamReaderPrivate> d_ptr;

};
#endif // QT_NO_XMLSTREAMREADER

  

 

4.1 TokenType 枚举解析:XML 文档的事件类型系统

4.1.1  枚举的核心作用 ( 1. 事件驱动解析的基础 &  2. 节点类型快速判断 & 3. 错误检测与恢复)

 流式解析器通过识别不同 TokenType 来驱动处理逻辑,例如:

while (reader.readNext()) {
    switch (reader.tokenType()) {
        case QXmlStreamReader::StartElement:
            processStartElement();
            break;
        case QXmlStreamReader::Characters:
            processTextContent();
            break;
        // 其他类型处理...
    }
}

提供便捷的类型检查接口:

if (reader.isStartElement()) {  // 等价于 tokenType() == StartElement
    // 处理开始元素
}
if (reader.isComment()) {       // 等价于 tokenType() == Comment
    // 处理注释
}

  

错误检测与恢复

待补充

  

4.1.2  TokenType - 典型应用场景

1. 元素结构识别

// 解析如下 XML:
<library> 
<book id="b001">
<title>Effective C++</title>
<author>Scott Meyers</author>
</book>
</library> if (reader.tokenType() == StartElement && reader.name() == "book") { // 此时解析器位于 <book id="b001">标签,处理book元素属性 QString id = reader.attributes().value("id").toString(); // id = "b001" while (reader.readNext()) {
// 第一次循环 : 定位到 <title> 元素 if (reader.tokenType() == StartElement && reader.name() == "title") {
// 此时解析器位于< title > 标签 reader.readNext(); // 移动到Characters,即标签内的文本节点 if (reader.tokenType() == Characters) { QString title = reader.text().toString(); // title = "Effective C++" } } else if (reader.tokenType() == EndElement && reader.name() == "book") { break; // 结束book元素处理 } } }

 

 

2. 文本内容与注释区分

if (reader.tokenType() == Characters) {
    if (!reader.isWhitespace()) {  // 过滤空白字符
        processRealText(reader.text());
    }
} else if (reader.tokenType() == Comment) {
    qDebug() << "注释内容:" << reader.text().toString();
}

  

3. DTD 与处理指令解析 - 不研究

if (reader.tokenType() == Invalid) {
    qDebug() << "解析错误位于第" << reader.lineNumber() 
             << "行,第" << reader.columnNumber() << "列";
}

  

 

4.1.3 

4.1.4 

4.1.5 

4.1.6 

  

 

4.2

 

4.3

 

4.4

 

 

 

 

STEP5、

 

STEP6、

 

STEP7、

 

STEP8、

 

STEP9、

 

STEP10、

 

STEP

 

posted on 2025-06-01 09:36  疯狂の阳光  阅读(56)  评论(0)    收藏  举报

导航