• DuiLib 源码分析之解析xml类CMarkup & CMarkupNode 头文件


    xml使用的还是比较多的,duilib界面也是通过xml配置实现的

    duilib提供了CMarkkup和CMarkupNode类解析xml,使用起来也是比较方便的,比较好奇它是怎么实现的,如果自己来写一个

    解析又需要怎样架构,架构之路还很遥远。。。

    先来看看头文件吧,CMarkup主要是用于分割xml,判断xml格式是否正确;CMarkupNode主要是将CMarkup分割的xml,获取节点中的属性,

    最多支持64个属性

      1 enum
      2 {
      3     XMLFILE_ENCODING_UTF8 = 0,//定义编码,默认使用utf8
      4     XMLFILE_ENCODING_UNICODE = 1,
      5     XMLFILE_ENCODING_ASNI = 2,
      6 };
      7 
      8 class CMarkup;
      9 class CMarkupNode;
     10 
     11 
     12 class UILIB_API CMarkup//其实比较容易看懂
     13 {
     14     friend class CMarkupNode;
     15 public:
     16     CMarkup(LPCTSTR pstrXML = NULL);
     17     ~CMarkup();
     18 
     19     bool Load(LPCTSTR pstrXML);
     20     bool LoadFromMem(BYTE* pByte, DWORD dwSize, int encoding = XMLFILE_ENCODING_UTF8);//从内存中加载解析
     21     bool LoadFromFile(LPCTSTR pstrFilename, int encoding = XMLFILE_ENCODING_UTF8);//从文件中加载解析
     22     void Release();
     23     bool IsValid() const;
     24 
     25     void SetPreserveWhitespace(bool bPreserve = true);
     26     void GetLastErrorMessage(LPTSTR pstrMessage, SIZE_T cchMax) const;
     27     void GetLastErrorLocation(LPTSTR pstrSource, SIZE_T cchMax) const;
     28 
     29     CMarkupNode GetRoot();
     30 
     31 private:
     32     typedef struct tagXMLELEMENT
     33     {
     34         ULONG iStart;//节点开始指针位置
     35         ULONG iChild;//第一个孩子节点指针位置
     36         ULONG iNext;//下一个兄弟节点指针位置
     37         ULONG iParent;//父亲节点指针位置
     38         ULONG iData;//节点属性结束的位置
     39     } XMLELEMENT;
     40 
     41     LPTSTR m_pstrXML;//xml内存开始位置
     42     XMLELEMENT* m_pElements;//数组储存节点信息
     43     ULONG m_nElements;
     44     ULONG m_nReservedElements;
     45     TCHAR m_szErrorMsg[100];
     46     TCHAR m_szErrorXML[50];
     47     bool m_bPreserveWhitespace;
     48 
     49 private:
     50     bool _Parse();
     51     bool _Parse(LPTSTR& pstrText, ULONG iParent);//解析xml函数,主要是这里解析
     52     XMLELEMENT* _ReserveElement();//如果数组不够长则扩充
     53     inline void _SkipWhitespace(LPTSTR& pstr) const;
     54     inline void _SkipWhitespace(LPCTSTR& pstr) const;
     55     inline void _SkipIdentifier(LPTSTR& pstr) const;
     56     inline void _SkipIdentifier(LPCTSTR& pstr) const;
     57     bool _ParseData(LPTSTR& pstrText, LPTSTR& pstrData, char cEnd);//解析属性的值
     58     void _ParseMetaChar(LPTSTR& pstrText, LPTSTR& pstrDest);//处理一些转义符号
     59     bool _ParseAttributes(LPTSTR& pstrText);//解析属性
     60     bool _Failed(LPCTSTR pstrError, LPCTSTR pstrLocation = NULL);
     61 };
     62 
     63 
     64 class UILIB_API CMarkupNode
     65 {
     66     friend class CMarkup;
     67 private:
     68     CMarkupNode();
     69     CMarkupNode(CMarkup* pOwner, int iPos);
     70 
     71 public:
     72     bool IsValid() const;
     73 
     74     CMarkupNode GetParent();
     75     CMarkupNode GetSibling();
     76     CMarkupNode GetChild();
     77     CMarkupNode GetChild(LPCTSTR pstrName);
     78 
     79     bool HasSiblings() const;
     80     bool HasChildren() const;
     81     LPCTSTR GetName() const;
     82     LPCTSTR GetValue() const;//这里获取不到节点的值,它返回的IData其实是属性末尾
     83 
     84     bool HasAttributes();
     85     bool HasAttribute(LPCTSTR pstrName);
     86     int GetAttributeCount();
     87     LPCTSTR GetAttributeName(int iIndex);
     88     LPCTSTR GetAttributeValue(int iIndex);
     89     LPCTSTR GetAttributeValue(LPCTSTR pstrName);
     90     bool GetAttributeValue(int iIndex, LPTSTR pstrValue, SIZE_T cchMax);
     91     bool GetAttributeValue(LPCTSTR pstrName, LPTSTR pstrValue, SIZE_T cchMax);
     92 
     93 private:
     94     void _MapAttributes();//将之前分割好的xml映射到m_aAttributes中储存起来
     95 
     96     enum { MAX_XML_ATTRIBUTES = 64 };
     97 
     98     typedef struct
     99     {
    100         ULONG iName;
    101         ULONG iValue;
    102     } XMLATTRIBUTE;
    103 
    104     int m_iPos;
    105     int m_nAttributes;
    106     XMLATTRIBUTE m_aAttributes[MAX_XML_ATTRIBUTES];
    107     CMarkup* m_pOwner;//指向CMarkup指针,节点属性及值都是从这里获取
    108 };

    简单说一下这两个类的工作原理,首先用CMarkup加载xml入内存,在将其分割字符串,建立节点树的关系(通过XMLELEMENT*指向节点位置关系,iStart指向节点开始部分,iData指向节点末尾,iChild,iNext,iParent储存节点之间的关系),获取节点是属性则通过CMarkupNode根据节点iStart,iData的值进行属性提取。CMarkupNode用于获取属性值及获取父亲,兄弟,儿子节点,熟悉了这两个类的作用,使用起来就比较方便了,具体实现下次再详细说明。

  • 相关阅读:
    python读写操作(txt, mat, xls, etc文件)
    开发linux版QQ就是支持未来的国产操作系统
    为知笔记linux绿色版的快速调用
    数学物理中的常见误区
    markdown语法小结
    信息爆炸时代的知识获取
    matlab: 数据的读写
    APS期刊投稿准备: REVTex格式
    markdown基本语法
    常见的数学关系
  • 原文地址:https://www.cnblogs.com/george-cw/p/5372135.html
Copyright © 2020-2023  润新知