XML:在 C++ 应用程序中包含灵活的解析器






4.84/5 (132投票s)
免费、可移植、与编译器无关的 C++ XML 库
包含
- XML 类源文件(XML.CPP、XML.H、MIME.H)
- 文档(XML.CHM)
- 测试项目 XMLTEST(cpp/sln/vcproj)
- 以下已编译的应用程序:Win32 的 TXML.EXE,Windows Mobile 5+ 设备的 XMLPPC.EXE。
- XDB.CPP,演示了 XML 库在创建配置对话框中的用法。
- XML.JAVA,库在 Java 中的实验性实现。
引言
您是否厌倦了市面上众多的非可移植 XML 解决方案?试试我的库吧。它可以在任何操作系统和任何编译器中运行。无 MFC、无 COM、无全局变量,纯粹的 C++!
特点
- 可移植,基本功能可在任何环境中运行 - 我已在 Microsoft Visual C++ 2005、Borland、GCC、Codewarrior、Pocket PC 2003+ 中进行过测试,并支持 Windows、Linux、Windows Mobile 和 Symbian 操作系统
- 基于类的操作或 INI 风格的包装器
- UTF-8 和(Win32)UTF-16 读/写支持
- 从文件、内存或(Win32)URL 导入
- (Win32)读取/保存加密的 XML 文件;自定义加密
- 导出到文件、内存或(Win32)注册表项
- 数据库查询(Win32)
- 允许 XML 内存压缩
- 完整性测试
- 允许“即时”创建变量和返回值
- 元素/变量/注释/内容创建、删除、排序、移动、比较
- 允许以文本形式在 Windows 剪贴板之间复制/粘贴 XML 元素
- 能够通过 ADO(Win32)导入数据库
- JSON 转换器
- 支持
&vars
; - 在变量中保存/加载二进制数据(需要 mime.h)
- 支持
CDATA
- 支持元素卸载和重新加载
- XML 元素更新
- 支持临时变量
- 支持二进制输入/输出
- HTML 帮助
- Java 实现
- 支持每个元素的加密/解密(在 Windows 下),支持对称密钥和非对称(证书)。
- 支持每个元素的签名/验证(在 Windows 下)使用证书。
- x64 兼容性
- 实验性 JSON 支持。
- 2 个版本:带 STL / 不带 STL。
许可证
对于任何类型的免费、共享软件、商业软件或任何其他类型的项目,本库均免费使用,只要您
- 在您的应用程序文档和/或关于框中注明我的署名
- 在我的论坛(http://www.turboirc.com/forum)注册,以便您收到有关该库的更新和新闻
- 通过论坛给我发送一条消息,告知您的应用程序名称(如果它将被发布),以便我可以链接到您。
无 STL 版本
STL 和异常处理在任何 C++ 实现中都还不可用 - 例如,Symbian OS SDK 中不存在 STL。因此,我决定使用我自己的 Z<>
类(在 xml.cpp 中定义)来操作缓冲区。
无 STL 版本,带 STL 扩展
如果您使用非 STL 版本但仍启用 STL,可以在包含 xml.h 之前定义 XML_USE_STL_EXTENSIONS。这允许 XMLVariable 和 XMLContent 返回 std::string 作为其值(因此您无需先查询大小),并具有 GetValueS() 成员。
STL 版本
对于新代码,您可以在包含 xml.h 之前定义 XML_USE_STL
来使用 STL。这将生成更快、更安全的代码,但请注意,它与非 STL 版本不完全兼容,因此如果您将代码从非 STL 版本移植到 STL 版本,则需要进行一些更改。
STL 版本使用 std::vector
、std::string
和标准算法。
使用类操作 XML
共有 7 个类
XML
管理 XML 文件:打开、保存、导出等。XMLHeader
管理 XML 头(XML 头可以包含注释)XMLComment
管理 XML 注释XMLContent
管理 XML 内容XMLElement
管理 XML 元素XMLVariable
管理 XML 变量XMLCData
管理 XML 自定义数据
我将不详细描述这些类的所有成员函数,因为我的帮助文件中已经有了描述。在这里,我将演示它们的基本用法。请注意,该库不使用异常处理或 STL,因为这两者并非在所有 C++ 实现中都存在(例如 Symbian)。
下面的代码加载一个 XML 文件,然后检查完整性并压缩内存。test.xml 是我使用的示例文件。请注意,元素/变量名称区分大小写。
XML* a = new XML("f.xml"); // load from file
XML* a = new XML("<blah f="\">",1); // load from memory from ASCIIZ string
XML* a = new XML("http://www.some.com/files.xml",2); // load from URL(Win32)
ASSERT(a->IntegrityCheck() == true && a->ParseStatus() == 0);
a->CompressMemory();
//Get 3rd element's name, and its variable "v" value.
//Also set new variable "tz" with normal and with 'on the fly' mode
char y[100] = {0};
a->GetRootElement()->GetChildren()[0]->GetElementName(y);
// now y == "Cfg"
a->GetRootElement()->GetChildren()[0]->FindVariableZ("v")->GetValue(y);
// now y == "Cfg"
// Create "tz" in the 'normal' mode
XMLElement* e = a->GetRootElement()->GetChildren()[0];
XMLVariable* v = new XMLVariable("tz","some value");
e->AddVariable(v);
// now do not delete v, it is owned by e
// Create "tz" on the fly
a->GetRootElement()->GetChildren()[0]->FindVariableZ( "tz",true)->
SetValue("some value");
// FindVariableZ(x,true) creates the var if doesn't exist!
// Create Comments and Contents in the same way.
// Use 0 instead of y to get the # of bytes required </blah>
// <blah f="\">for the returned string.
// Let's save/export:
if (a->IntegrityTest())
{
a->Save(); // Saves back to file
a->Save("new.xml");
a->Export(fp,1,0,0); // Save to a fp. You can also export to memory
// or save only one element by calling XMLElement :: Export.
delete a;
// bye bye; </blah>
// <blah f="\">Note that the destructor doesn't save the file by default,
//unless you call XML :: SaveOnClose(). }</blah>
使用 INI 风格的包装器操作 XML 文件
现在您可以使用一些 INI 风格的函数,而不是 WritePrivateProfileString
。
XMLSetString
XMLGetString
XMLSetInt
XMLGetInt
XMLSetBinaryData
XMLGetBinaryData
XMLSetFloat
XMLGetFloat
这些函数可以独立工作,也可以与已打开的 XML 对象一起工作。当将有效的 XML 对象传递给它们时,它们会修改该对象。当将文件名传递给它们时,它们会创建一个 XML 对象,加载文件,读/写该文件,然后将其保存回原样,这与 INI 文件函数非常相似。
由于这些函数接受它们的元素作为带有 \
的 string
(例如,Cfg\\Amplify
),因此您只能操作具有唯一元素名称的 XML 文件。否则,将导致文件损坏。
现在让我们尝试获取/设置我们 XML 文件中的一些数据。
char y[1000] = {0};
XMLGetString("Cfg","v","",y,1000,"test.xml");
// This gets 'Bowlingy' to y.
XMLGetString("Cfg\\Amplify","V","not_found",y,1000,"test.xml");
// This gets 'not_found' to y. Variables/Elements are case sensitive!
XMLSetString("A\\B\\C","v","hahaha","test.xml");
// Elements A B C are created!
Fread(y,1,100,some_file);
XMLSetBinaryData("A\\B\\C","v",y,100,"test.xml");
// Binary data can be saved/read, encoded with Base64 (mime.h)
请注意,所有这些 string
函数都需要 UTF-8 string
。如果您在 Windows 下,您也可以使用 wchar_t
值调用 XMLSetString
,库会通过使用 WideCharToMultiByte
自动将其转换为 UTF-8。
卸载和重新加载
使用 XMLElement::UnloadElement
、ReloadElement
将元素临时保存到内存文件中(详情请参阅帮助文件)。这使您能够在不浪费 RAM 的情况下操作大型 XML 文件。
即将实现 XML::PartialLoad()
。
项目借用
使用 XMLElement::BorrowItem
从另一个 XMLElement
* 添加一个 XMLElement
* 镜像。这是一个高级功能,必须谨慎使用,否则您的应用程序将因严重的堆栈溢出而崩溃。请阅读帮助文件了解详情。
临时变量
临时元素是一个 XMLElement
(或 XMLVariable
),其“temporal”标志已设置。您可以通过调用 SetTemporal
和 GetTemporal
成员函数来设置或查询此标志。默认情况下,元素和变量不是临时的。
您也可以通过构造函数标志创建临时元素或变量。此外,XMLElement::FindElementZ()
和 XMLElement::FindVariableZ
(可以即时创建元素/变量)也可以将其标记为临时。
当您调用 XMLElement::RemoveTemporalElements(bool Deep)
时,所有临时子元素都会被删除。如果 Deep
为 true
,则其所有子元素的临时元素也会被删除。如果一个元素是临时的并且被删除,那么它的所有子元素自然也会被删除,即使它们没有被标记为临时。因此,例如将根元素标记为临时,在调用 RemoveTemporalElements()
时将导致整个 XML 文件被销毁。
当您调用 XMLElement::RemoveTemporalVariables(bool Deep)
时,该元素的所有临时变量都会被删除。如果 Deep
设置为 true
,则其所有子元素的临时变量也会被删除。
当您调用 XML::RemoveTemporalElements()
时,它会对根元素调用 XMLElement::RemoveTemporalElements(true)
和 XMLElement::RemoveTemporalVariables(true)
。
请注意,除非您使用上述函数手动删除临时元素,否则它们不会被删除 - 它们被视为普通元素/变量,并正常保存或导出。
使用 Unicode 字符串与库
该库使用 UTF-8,这意味着传递和返回的 string
是 char*
。为了将 Unicode string
传递给该库,您必须手动将其转换为 WideCharToMultiByte(CP_UTF8,...);
。我创建了一个非常简单的包装器,可以将其作为类来完成。
class W{public:W(const wchar_t* x){int y = wcslen(x);int wy = y*2 + 100;
we = new char[wy];memset(we,0,wy);WideCharToMultiByte(CP_UTF8,0,x,-1,we,wy,0,0);
}~W(){delete[] we;}operator char* (){return we;}};
因此,如果您有一个 Unicode string x
并想在我的库中使用它,您将使用 W(x)
,它将您的 Unicode string
转换为 UTF-8 string
,通过运算符使用它,并在析构函数中释放它。
64 位兼容性
该库支持 64 位兼容性;您将能够在任何 64 位编译器下毫无问题地编译和使用它。
元素更新
有时您需要用另一个元素的元素和变量来更新一个 XMLElement
。
int UpdateElement(XMLElement* NewEl,bool UpdateVariableValues = false);
这将
- 尝试
NewEl
的所有变量。如果其中任何一个在您的当前元素中也存在,那么如果UpdateVariableValues == true
,该函数将更新变量。如果NewEl
的变量在您的元素中不存在,则将其复制。 - 尝试
NewEl
的所有元素。如果当前元素中不存在NewEl
的任何元素,则将其复制。如果存在,则该函数调用UpdateElement
对该元素与其子元素NewEl
进行操作,从而递归更新所有孙子元素和变量。
通过 ADO 导入数据库
使用 XML::ImportDB()
导入数据库。您需要处理两个结构。
struct IMPORTDBTABLEDATA { char name[256]; char itemname[100];
int nVariables; char** Variables; char** ReplaceVariables; };
struct IMPORTDBPARAMS { char* dbname; char* provstr;
int nTables; IMPORTDBTABLEDATA* Tables; };
您需要填写 IMPORTTDBPARAMS
,其中包含名称(可选)、提供程序 string
(有关详细信息,请参阅 ADO 文档)、要导入的表数,然后为每个表填写一个 IMPORTDBTABLEDATA
结构 - 其中包含表名、要存储的 XMLElement*
项名、要获取的变量数(表中的列数),以及指向变量名和要存储的变量名的双指针。例如,请参阅 xmltest.cpp。
数据库查询
您可以使用 XMLElement::XMLQuery()
,它接受一个要测试的表达式、搜索深度(如果需要查询所有子元素,则为 -1
),以及指向返回的 XMLElement*
的指针(这些元素不会被复制,函数只是将它们的指针复制到您的数组中)。示例如下:
XMLElement* e = ... ; // get this from somewhere
int nC = e->GetAllChildrenNum();
XMLElement* a = new XMLElement*[nC];
memset(a,0,sizeof(XMLElement*)*nC);
int nR = e->XMLQuery("some_var == \"*5*\"",a,-1);
for(int i = 0 ; i < nR ; i++)
{ ...
// use a
}
delete[] a;
上面的代码返回所有具有名为“some_var
”的变量的子元素的指针,该变量的值包含“5
”(支持正则表达式)。有关更多信息,请参阅 XML.CHM。
STL 模式对 XMLElement 的更改
- 请注意,
XMLHeader
、XMLContent
、XMLComment
和XMLCData
也有一些微小的更改,但它们对应用程序是透明的。如果您使用 STL 版本,您需要注意以下列表总结的更改。 - 现在,复制构造函数和运算符
=
允许直接复制或以其他方式复制XMLElement
。XMLElement(const XMLElement&); XMLElement& operator =(const XMLElement&);
- 以下函数使用引用。
XMLElement& operator[](int); XMLElement& AddElement(const char*,int p = -1,bool Temp = false); XMLElement& AddElement(const XMLElement&,int p = -1);int Compare(XMLElement&);
这些函数使用引用而不是指针。此外,
AddElement
已扩展,增加了插入位置(或-1
表示添加到末尾),并且InsertElement
已被移除。 -
int RemoveElementAndKeep(unsigned int i,XMLElement* el);
这将被移除的元素存储在传递的指针中。
- 不支持项目卸载(
UnloadElement
/ReloadElement
)。 - 不支持项目借用。
- 项目排序使用
std::sort
。 XMLElement* Duplicate(XMLElement* = 0)
仍然返回指针,而不是引用。GetComments()
、GetContents()
、GetVariables()
、GetCDatas()
和GetChildren()
返回std::vector<>
。此外,函数AddComment()
、AddCData()
、AddVariable()
、AddElement()
和AddContent()
返回对添加项的引用。GetAllChildrenNum()
仍返回指针。
对称元素加密/解密
从 Windows 上的版本 0x158 开始,该库为元素提供了对称(基于密码)的加密/解密功能。XMLElement
提供了 4 个新函数,两个用于就地加密/解密子元素,两个用于自我复制为加密/解密形式。整个元素都被加密,包括所有子元素、变量、注释和内容。
加密的 XML 元素是一个普通的 XML 元素,其中包含 1 个内容,该内容以加密形式存储了元素的所有内容。您可以像处理普通 XML 文件一样处理加密的 XML 文件,无论其中是否包含加密元素。
-
XMLElement* XMLElement :: Encrypt(const char* pwd);
-
XMLElement* XMLElement :: Decrypt(const char* pwd);
这两个函数会自行加密/解密到一个新返回的 XMLElement
中(请记住删除它或将其分配给另一个 XMLElement
)。使用 AES-256 和 SHA-1 哈希。如果出于任何原因加密或解密失败,它们将返回 0
。
-
bool EncryptElement(unsigned int i,char* pwd);
-
bool DecryptElement(unsigned int i,char* pwd);
这些函数就地加密指定的子元素,成功时返回 true
,失败时返回 false
。
每个加密的 XML 元素都可以像普通 XMLElement
一样解析,只包含 1 个内容数据。请注意,密码未存储,因此如果您丢失了密码,XML 数据将无法访问。
该库使用 CryptoAPI
来加密/解密数据。
元素签名/验证
版本 0x15A 提供了 3 个用于签名/验证的成员函数。
-
bool XMLElement::SignElement(unsigned int i,PCCERT_CONTEXT pCert);
-
bool XMLElment::RemoveSignature(unsigned int i);
-
bool XMLElement::VerifyDigitalSignature(unsigned int i,PCCERT_CONTEXT* ppCert);
SignElement
使用提供的证书为索引为 i
的元素签名。元素签名将作为名为 __signature__
的二进制值添加到元素中。如果签名已存在,函数将失败。如果证书无效、没有 private
密钥或发生其他错误,函数将失败。
RemoveSignature
函数从元素中删除签名(仅删除名为 __signature__
的变量)。
VerifyDigitalSignature
函数验证索引为 i
的元素,并返回与签名匹配的证书。证书不一定受信任;您必须实际检查证书链以验证其来源。
如果索引 i
为 -1
,则这些函数将应用于其自身元素。
非对称加密/解密
版本 0x15B 提供了 2 个用于非对称加密/解密的成员函数。
-
XMLElement* EncryptElement(unsigned int i,PCCERT_CONTEXT* pCert,int nCert);
-
XMLElement* DecryptElement(unsigned int i,PCCERT_CONTEXT* ppCert);
EncryptElement
使用提供的证书列表加密索引为 i
的元素(如果 i == -1
,则为自身)。该函数返回一个 XMLElement*
,其中包含整个 XMLElement
的加密表示,如果发生错误,则返回 0
。
DecryptElement
函数使用“个人”存储中的任何证书解密索引为 i
的元素(如果 i == -1
,则为自身)。如果 ppCert
不为 null
,则返回用于解密元素的证书。它返回一个 XMLElement*
,即原始元素。
请注意,与基于密码的对称加密不同,非对称加密需要证书的 public
密钥进行加密,需要 private
密钥进行解密。因此,例如,如果您使用 PC 中的 CA 根证书之一加密一个元素,该元素将正常加密,但如果没有 private
密钥,您将永远无法解密它。
二进制输入/输出
XML 文件可能很大,加载可能需要一段时间。该库已针对速度进行了优化,但如果需要最大性能,您可以尝试 ImportFromBinary
和 ExportToBinary
函数。XML
、XMLElement
、XMLVariable
、XMLComment
、XMLContent
、XMLCData
和 XMLHeader
都提供了上述两个函数。
XML* x = new XML("somefile.xml");
BDC b = x->ExportToBinary();
// BDC is just a data container with member .size() to get the
// size of the data and p() to get a pointer to the data.
x->ImportFromBinary(b);
使用二进制输入和输出将导致您的二进制 XML 文件在库升级且二进制输入和输出发生更改时变得无用,但对于长期使用,您可以考虑使用它。
JSON 解析器
XML 很好,但一些数据仍以 JSON 格式显示。XML.CPP 现在包含一个实验性的 JSON 转换器。
Java 实现
好的,C++ 很完美,但我现在正在为使用 Java 的 Android 编写代码。XML.JAVA(包含在 zip 文件中)提供了该库的 Java 实现,具有非常相似的类和方法。当然,并非所有 C++ 方法都受支持,但它仍然是满足您 Java 需求的快速解决方案。
iOS 兼容性
该库在 iOS 和 XCode 中运行良好。
其他特性
以下是一些其他当前功能:
- 使用
XML::ImportDB()
将数据库(支持所有 ADO 数据库)导入 XML 元素(帮助文件中提供了示例)。 - 使用
XML::Query()
查询数据库。
以下是一些我未来想实现的功能:
- 不区分大小写的函数
- 部分 XML 加载/保存
- XML 压缩
请留下您的问题和评论!
示例项目
XMLTest
:一个命令行演示,用于探索库的主要功能。TXML
:Win32 的完整数据库/XML 文件解决方案:利用了库的所有强大功能。特点:- MDI XML 加载器
- 从文件、URL、加密文件(AES 256)、导入 ADO 数据库、加载剪贴板加载,待办:加载部分
- 保存到文件、加密文件、导出文本、导出到注册表项
- 复制/剪切/粘贴、复制/剪切/粘贴到 Windows 剪贴板、复制/剪切追加、重命名、删除
- XML 完整性检查、XML 压缩
- 查看菜单:尚未实现,除了“切换视图” F4,它会切换到
- 纯 XML
- 数据库 - 类型 XML(非常适合存储表等数据库类型项)。网格样式编辑器
- 纯文本
- 插入元素/变量/注释/内容
- 执行查询,打开一个包含查询结果的新 XML 文件。
- 从 Internet 自动更新
- 支持二进制 I/O。
- 支持元素加密/解密。
- 注意:不自动保存加载的 XML 文件,并且在未检查是否已保存的情况下关闭它们。请手动按 Ctrl+S 保存文件。
- 注意:无撤销功能。如果您弄乱了,我很抱歉
" />
XMLPPC
:Windows Mobile 5+ 的精简 XML 编辑器。支持 TXML 的所有功能,但不支持多文件打开和数据库查询。Turbo GPS
:Android 的端口使用了新的 Java 实现。试试吧!
历史
- 2014 年 6 月 26 日 - 更新 0x170 - 在 C++/Java 版本中添加了一些助手。
- 2012 年 11 月 16 日 - 更新 0x16B
- 为 XMLElement 添加了 Next() 和 Prev() 以获取兄弟节点。
- 为 XMLVariable 和 XMLContent 添加了 GetValueS(),以便在启用了 XML_USE_STL_EXTENSIONS 时将其值作为 std::string 获取。
- 完全支持 iOS。
- 修复了 GetAllChildren() 中返回子节点在其父节点之前的错误。
- 增加了与 XML 第二个头文件的兼容性。现在 XMLHeader 可以包含主头和其下的另一个头。
- 将 %llu sprintfs 替换为标准 long-long 而不是 MS 兼容的 %I64 前缀。
- 2012 年 8 月 8 日 - 更新 0x169
- 启用了 XML 头 <!data >。
- 将 JSON 添加到主 xml.cpp 中。
- 一些小错误修复。
- 2012 年 1 月 24 日 - 更新 0x165
- STL 索引错误修复
- STL 加载时内存泄漏错误修复
- 2011 年 10 月 13 日 - 更新 0x164
- 各种错误修复
- 添加了 json 实验性转换器
- 2010 年 12 月 30 日 - 更新 0x162
- 添加了二进制输入/输出
- 修复了一些 GCC 兼容性问题
- 修复了一些 STL 问题
- 添加了 Java 实现
- 2010 年 3 月 9 日 - 更新 0x15B
- 修复了 STL 错误
- 基于
CryptoAPI
证书添加了非对称加密/解密(Win32)
- 2010 年 3 月 7 日 - 更新 0x15A
- 修复了二进制变量中的错误
- 基于
CryptoAPI
证书添加了元素签名/验证(Win32)
- 2009 年 11 月 30 日 - 更新 0x158
- 元素加密、内容二进制项和 STL 增强
- 2009 年 8 月 9 日 - 更新 0x156
- 累积更新和修复
- 2009 年 1 月 15 日 - 更新 0x150
- 将
__int64
转换为long long
- 修复了小型解析错误
- 添加了 STL 模式
- 将
- 2008 年 10 月 20 日 - 更新 0x143
- 添加了可选命名空间
XMLPP
- 将“
Savemode
”、“Loadmode
”和“Targetmode
”的常量转换为可读的enum
s - 添加了额外的保护,以避免在格式错误的 XML 时崩溃。
- 将许多“
int
”替换为“size_t
”,允许进一步扩展到 X64 并消除 C4267
向更多函数添加了“Const
”
- 添加了可选命名空间
- 2008 年 7 月 23 日 - 更新 0x141
- 添加了注释包含
<
和>
的能力 - 修复了由于格式错误的 XML 文件导致的一些崩溃
- 向一些函数添加了
const
- 添加了
SetValueInt64
和GetValueInt64
- 修复了
SetValueInt
,使用%i
而不是%u
- 其他小修复
- 添加了注释包含
- 2008 年 4 月 27 日 - 更新 0x140
- 添加了
XML::SetUnicode()
- 修复了元素更新中的错误
- 将
Item
参数更改为 64 位 - 修复了 64 位
Z<>
中的一个小错误 - 修复了
XMLElement::MoveElement
中的错误 - 添加了临时元素
- 添加了
- 2007 年 11 月 22 日 - 更新 0x139
- 一些错误修复
- 使用
XMLElement::UpdateElement
进行项目更新
- 2007 年 10 月 31 日 - 更新 0x136
- 添加了项目借用和镜像
- 2007 年 10 月 22 日 - 更新 0x135
XML::XML
、XML::Load()
和XML::Save()
接受 Unicode 文件名
- 2007 年 10 月 13 日 - 更新 0x132
- XML 现在兼容 x64
- 添加了 XDB.CPP 来演示
XMLDialog()
的用法
- 2007 年 9 月 4 日 - 更新 0x12F
- 元素卸载/重新加载的实现
- 2007 年 8 月 20 日 - 更新 0x12E
- 更快地保存到内存
- 2007 年 8 月 19 日 - 更新 0x12D
- 修复了
XMLQuery
错误 - 修复了格式错误的 XML 错误
- 添加了
XMLElement::AddElement
、AddVariable
、AddComment
、AddContent
、AddCData
的文本版本
- 修复了
- 2007 年 8 月 7 日 - 更新 0x12B
- 修复了
CData
错误 - 修复了序列错误
- 修复了
- 2007 年 6 月 22 日 - 更新 0x129
- 修复了
CData
错误 - UTF-16 写入支持
- 修复了
- 2007 年 6 月 21 日 - 更新 0x128
- 添加了
XMLCData
- 修复了 gcc/utf-16 的一些次要错误
- CHM 帮助文件格式
- 添加了
- 2007 年 6 月 8 日
- 添加了 TXML.EXE(用于 Win32),利用了库的所有功能(目前仅提供二进制文件,无源代码)。
- 2007 年 6 月 1 日 - 更新 0x125
- 修复了 Pocket PC 错误,更新了
XML::XMLQuery()
- 修复了
AddBlankVariable
错误 - XMLPPC.EXE Pocket PC 示例
- 修复了 Pocket PC 错误,更新了
- 2007 年 5 月 18 日 - 更新 0x124
- UTF-16 文件读取
- 修复了 Linux 编译
- 修复了
XML::ImportDB()
- 其他问题
- 2007 年 5 月 15 日 - 更新 0x123
- 在 XML.CPP 中包含格式化选项
- 2007年5月9日
- 发布了原始版本