1. 程式人生 > >寫了一個mircro XML解析器,附原始碼

寫了一個mircro XML解析器,附原始碼

不喜歡看人廢話喜歡直奔主題的是同學可以直接: goto 附件下載


  mirco 的意思是比 tiny 還要 tiny。

  GUI 模板用 XML 做是最合適的。方便嵌入指令碼,方便編輯修改,方便嵌入面板描述,用 XML 做模板,寫起 GUI 編輯器也要方便得多。

  以前幾個的 GUI 模板解析器用的是 MSXML 來實現的,不過它提供的介面字串型別全是 BSTR,自己的介面又是 TCHAR*,每一次的呼叫都會有一次字串轉換,效率很低。而且一想到程式碼裡有 QueryInteface,AddRef,Release ,心裡就不踏實,擔心吊膽的。

  於是又打算用 TinyXML,看了幾遍程式碼,發現它對寬字符集的支援有些古怪。程式碼裡其它的雜七雜八的東西有點多,程式碼風格什麼的也不大喜歡。

  於是自己寫了一個簡單的,雖然有錯誤檢測機制,不過沒有提供查詢介面,因為這樣我覺得使介面不整潔。其實要知道 XML 哪裡出錯了很簡單,隨便拿個瀏覽器開啟就行了,提示得非常詳細。不過以後可能會根據需要新增上。XPATH 支援也是如此。介面函式全部使用 UNICODE。

測試程式碼:

   1: // cexer
   2: #include "./include/XML/xmlfile.h"
   3: #include "./include/XML/xmlelement.h"
   4: #include "./include/XML/xmldeclaration.h"
   5:
#include "./include/XML/xmlunknown.h"
   6: #include "./include/XML/xmlcomment.h"
   7: #include "./include/XML/xmltext.h"
   8: #include "./include/XML/xmlattribute.h"
   9:  
  10: using namespace cexer;
  11: using namespace cexer::xml;
  12:  
  13:  
  14: // c++ std
  15: #include
<iostream>
  16: using namespace std;
  17:  
  18:  
  19: int wmain( int argc,WCHAR** argv )
  20: {
  21:     wcout.imbue( std::locale("chs") );
  22:  
  23:     XmlFile document( L"./XMLs/utf16le_ns.xml" );
  24:     if ( !document.load() )
  25:     {
  26:         wcout<<L"解析失敗"<<endl;
  27:         return 0;
  28:     }
  29:  
  30:     XmlElement* root = document.element();
  31:     if ( !root )
  32:     {
  33:         wcout<<L"沒有找到根結點"<<endl;
  34:         return 0;
  35:     }
  36:  
  37:     wcout<<root->name()<<endl;
  38:  
  39:  
  40:     XmlNode* firstChild = root->firstChild();
  41:     if ( !firstChild )
  42:     {
  43:         wcout<<L"沒有子結點"<<endl;
  44:         return 0;
  45:     }
  46:  
  47:     XmlDeclaration* declar = xml_cast<XmlDeclaration*>( firstChild );
  48:     if ( !declar )
  49:     {
  50:         wcout<<L"第一個子結點不是宣告"<<endl;
  51:     }
  52:     else
  53:     {
  54:         wcout<<L"第一個節點是宣告"<<endl;
  55:         wcout<<L"version = "<<declar->version()<<endl;
  56:         wcout<<L"encoding = "<<declar->encoding()<<endl;
  57:         wcout<<L"standalone = "<<declar->standalone()<<endl;
  58:     }
  59:  
  60:     XmlComment* comment = xml_cast<XmlComment*>( firstChild->next() );
  61:     if ( !comment )
  62:     {
  63:         wcout<<L"第二個子結點不是註釋"<<endl;
  64:     }
  65:     else
  66:     {
  67:         wcout<<L"第二個結點是註釋:"<<comment->value()<<endl;
  68:     }
  69:  
  70:     XmlElement* window = root->element( L"window" );
  71:     if ( !window )
  72:     {
  73:         wcout<<L"沒有找到window元素結點"<<endl;
  74:         return 0;
  75:     }
  76:     wcout<<window->attributeValue( L"text" )<<endl;
  77:  
  78:  
  79:     XmlElement* nextWindow = window->nextElement( L"window" );
  80:     if ( !nextWindow )
  81:     {
  82:         wcout<<L"沒有找到後面的window元素結點"<<endl;
  83:     }
  84:     else
  85:     {
  86:         wcout<<L"後面還有一個window元素結點 ";
  87:         wcout<<nextWindow->attributeValue(_T("name"))<<endl;
  88:     }
  89:  
  90:     XmlElement* panel = window->element( L"panel" );
  91:     if ( panel )
  92:     {
  93:         wcout<<panel->attributeValue( L"caption" )<<endl;
  94:     }
  95:  
  96:     window->setAttribute( L"styleAdd",L"WS_VISIBLE" );
  97:     window->setAttribute( L"styleRemove",L"\";<>=&\"" );
  98:  
  99:     if ( !document.save( L"./XMLs/modified/utf16le_ns.xml" ) )
 100:     {    
 101:         wcout<<L"儲存失敗"<<endl;
 102:     }
 103:  
 104:     return 0;
 105: }

編碼支援:
  因為內部使用 MultiBytesToWideChar 和 WideCharToMultiBytes 來實現字符集/編碼的操作,因此對字符集/編碼的支援很靈活,能夠支援以上兩個函式支援的所有編碼,只需簡單的修改即可新增新的支援。預置了幾種編碼支援:

  1. UTF-16LE(UNICODE)
  2. GBK
  3. BIG5
  4. GB2312
  5. UTF-7
  6. UTF-8

  對於沒有編碼宣告並且沒有檔案頭簽名檔案,都視為 UTF-8 編碼。以上的程式碼當中的 XML 檔案就是一個沒有簽名,沒有宣告的 UTF-16LE 編碼的 XML 檔案。

  TinyXML 內部解析字串全是以 char*  型別來解析,只支援多位元組編碼如 UTF-8,ASCII,不支援 UNICODE 編碼。如對中文的支援就比較古怪,如果 XML 以 UTF-8 格式儲存,則設定“值”的時候必須自己把字串轉換為 UTF-8 再設定,而在取得值以後,則必須自己將它們從 UTF-8 轉換成 UNICODE 或 ASCII,否則就是亂碼。

  主要是 TinyXML 為了跨平臺,所以沒有像 MultiBytesToWideChar  和 WideCharToMultiBytes  這種函式的直接支援。不過如果是為了跨平臺,這兩個函式也可以考慮自己實現。

節點型別轉換:

  因為在記憶體當中,元素,註釋,文字,宣告等結點都是儲存為一個基類的指標,因此在使用的時候必須要有一個型別轉換的動作。也有一些 XML 解析器比較簡單,其中只有文件,元素,屬性這三種結點,記憶體當中存的全部都是元素集合,元素當中再存有屬性集合,用不著型別轉換,不過這種 XML 將 XML 讀入記憶體再存入磁碟檔案當中時,會丟失掉 XML 檔案原有的格式。

  TinyXML 在記憶體當中所有的結點(除屬性)都以基類 TiXmlNode 指標的形式存放 ,從一個 TiXmlNode* 進行型別轉的方法是這樣的:

  首先在基 TiXmlBase 宣告一組虛擬函式

   1: class TiXmlNode
   2: {
   3:     virtual TiXmlDocument*   ToDocument()    { return 0; }
   4:     virtual TiXmlElement*    ToElement()        { return 0; }
   5:     virtual TiXmlComment*    ToComment()     { return 0; }
   6:     virtual TiXmlUnknown*    ToUnknown()        { return 0; }
   7:     virtual TiXmlText*       ToText()        { return 0; }
   8:     virtual TiXmlDeclaration*    ToDeclaration() { return 0; }
   9: };

 
  然後在子類當中各自重寫向自己型別轉換的那一個虛擬函式。如在 XmlElement 和 XmlComment 當中:

   1: class XmlElement
   2: {
   3:     virtual TiXmlElement*    ToElement()        { return this; }
   4: };
   5:  
   6: class XmlComment
   7: {
   8:     virtual TiXmlComment*    ToComment()     { return this; }
   9: };


  這樣做很方便,不過如果要寫一個新的 XML 結點型別,就比較麻煩了,必須重新修改基類 TiXmlNode 的程式碼,整個 XML 解析器的程式碼都得重新編譯一遍。

  我則借用了 COM 的 Queryinterface 的方式。在基類 XmlCastable 當中聲明瞭一個虛擬函式 query,任意結點呼叫這個函式,輸入一個型別,若該結點是這個型別,那麼就輸出指標的值並返回 true,否則輸出 NULL 並返回 false。

相關推薦

一個mircro XML解析原始碼

不喜歡看人廢話喜歡直奔主題的是同學可以直接: goto 附件下載。   mirco 的意思是比 tiny 還要 tiny。   GUI 模板用 XML 做是最合適的。方便嵌入指令碼,方便編輯修改,方便嵌入面板描述,用 XML 做模板,寫起 GUI 編輯器也要方便得多。   以前幾個的 GUI 模板解

自己一個帶placeHolder的textView分享給大家

#import <UIKit/UIKit.h> @interface PlaceHolderTextView : UITextView {     UILabel *placeHolder;//編輯區 } @property(retain, nonatomic)

第三章 XML解析驗證轉換編輯

xml有這麼多的規則,寫出來的xml文字檔案到底符不符合要求呢? 用人工檢驗的方式效率太低,也容易出錯,所以開發出了程式來驗證。 xml驗證器: XML DTD和XML Schema,後者用來替代前者。 如果 XML 文件存在錯誤,那麼程式就不應當繼

最近開始努力學python 一個python小代碼:判斷一個登陸程序如果賬號密碼輸錯3次鎖定賬號無法再登陸

登陸 readlines 輸入 連續 nbsp 努力 一個 取數據 lis 1 count = 0 2 username = ‘zhangsan‘ 3 userpassword = ‘111111‘ 4 5 f = open(‘lock.txt‘,‘r+‘

原生JS一個小demo根據輸入的數字生成不同背景顏色的小方塊兒~

top == UNC 定位元素 demo TE tostring eight 地方 昨天練習寫了這個小demo,個人覺得通過設置定位元素left和top的值,來實現換行的功能,這種方法很巧妙~ 另外,如下代碼中的隨機顏色的獲取,還請各位前輩多多指教:需要改進的地方;或者有

CCF-棋局評估 201803-04(版本 2.0)------(之前一個臃腫的1.0版 還沾沾自喜 233)

核心 color namespace ace for play class 一個 while 核心 : 博弈搜索樹    雙方得分互為相反數    dfs (x,y,player): 玩家player下完(x,y)之後的得分最大值 易錯: 先判斷輸贏,再判斷

給女朋友用Python一個自動抽獎程序!Python在手獎品我有!

com () 單身 代碼 女孩子 nbsp 不能 是不是 apt 我相信大部分的女孩子都是喜歡買買買的,我還沒有見過不喜歡買東西的女孩子,當然很多東西也是有抽獎這項優惠的,很多小程序都有抽獎這個功能的,好了廢話不多說了,為了給女朋友寫這款抽獎程序,可謂是嘔心瀝血!不過看到她

最新用WPF為觸摸屏一個程序雙格輸入的

nload size alt wpf 一個 ast 點擊 fill fonts 原文:最新用WPF為觸摸屏寫了一個手寫程序,雙格輸入的 雙格輸入可以提高手寫速度,當前字寫完以後

一個預約東南大學體育場館的python指令碼目前剛剛實現功能後續會繼續完善

看到git上有人寫了一個自動預約的指令碼,正好前段時間在學python爬蟲和指令碼,索性也寫了一個,大佬直接略過。 目前沒有做圖形化,賬號和預約資訊也是手動輸入的,我也只寫了羽毛球和乒乓球,其實就是一個屬性的值。嫌麻煩的同學可以寫一個文字檔案,儲存這些資訊,然後倒入到腳本里,每次稍作修改就可以了。如果基友固

Python 運用所學知識製作一個歌詞解析要求:輸入時間給出對應歌詞

學了將近兩週python了,遇到了一道挺有意思的題分享一下:      製作一個歌詞解析器,要求:輸入一個時間點能給出對應時間的歌詞 廢話不多說,直接上圖,基本每步都有註釋: mulrc = '''[ti:藍蓮花] [ar:許巍] [al:留聲十年絕版青

繼續sprintf函式這次親自動手一個myprintf是不是更有意思當然別指望我的程式碼沒有bug。

#include <stdio.h> typedef char *va_list; #define __va_rounded_size(TYPE) \ (((sizeof(TYPE)+sizeof(int)-1)/sizeof(int))*sizeof(int

面對散落各處的收藏和筆記一個 App 用人工智慧來管理

你是否收藏了很多文章,回頭想用的時候卻不知道自己放在了哪個平臺,然後各個app都搜尋一遍?或者存了很多文章在pocket,卻從來沒有再看過?今天要給大家推薦一個知識的『聯結器』——優讀。 這是一款集收藏自動打標籤,待讀過期自動刪除,文章劃線筆記,圖書拍照識別筆記於一體的知識集中管理工具,更

剛學兩天python爬蟲一個分享給大家!爬蟲真的很簡單!

經過兩天的摸索,終於寫出了一個小小小爬蟲。這其中的波折是這樣的,聽我娓娓道來。我的電腦是沒有配置python環境的,所以首先要上官網下載python的環境檔案。 當然在學習Python的道路上肯定會困難,沒有好的學習資料,怎麼去學習呢? 學習Python中有不明白推薦加入交流群

並歸排序(看別人的看不懂自己一個排序思想是一樣的

public int[] intArray = {8,5,10,55,88,22,14,36,82,54,10,74,22}; @RequestMapping(value="hello") public int[] getHello(int[] intArray1) {

閒來無事用Python一個pm2.5查詢小程式還是很有趣的

    今天教大家用python完成首個MVP,如何用CLI(command-line interface,命令列介面)來執行第一個空氣質量查詢程式。 更多Python視訊、原始碼、資料加群960410445免費獲取   知識點

厲害!如何Python一個安卓APP原始碼

熱文導讀 | 點選標題閱讀 作者: “又耳的筆記本”  文末附原始碼地址 來源:http://youerning.blog.51cto.com/10513771/1733534 本文會帶大家寫一個Hello world並瞧一瞧Python版實現的android 2048的程式碼 前言

maven工程中controller下一個url請求冒404

昨天在controll層寫了一請求,但是訪問該url,冒404,特別古怪的一個問題。大哥給了我一個反編譯class軟體(檢視eclipse的編譯結果) 去eclipse編譯資料夾下找到該class檔案,發現並沒有寫入進去。 首先我做了clean下編譯軟體,但是效果是並沒有

自己一個c++ bitset功能非常齊全!

c++ bitset用途很廣,而理解它的最好方式莫過於自己寫一個,重新造輪子還是非常有樂趣的,廢話不多說了,貼程式碼。 首先是一些必要的函式,封裝在名字空間mystd裡面。/*如果發現有bug,望高手批評指正!相互交流交流! * 轉載本文的註明一下出處,謝謝! */ #

練習python一個四則運算程式支援乘方和“.3"這種格式

#!/usr/bin/python #coding=utf-8 # 本程式由使用者輸入一個表示式字串,然後計算這個表示式的值 # 表示式是一個四則運算表示式,可以包含^操作符# 注意:乘方用^運算子,支援".3"這種表示小數的形式。負數需要用括號擴起來 # 思路:利用棧的方