XML(eXtensible Markup Language可扩展标志语言)在近几年的信息类杂志、网站上可谓是最抢眼的一词。大大小小的信息产品都争相和它搭上关系,唯恐赶不及这辆快车。有着良好口碑的宝蓝
(Borland)系列开发平台也不例外,从6.0版开始就集成了XML组件包,因其使用MSXMLDom解析器,相比于此前广泛应用的XMLParser解析器,MSXMLDom更显规范、中文兼容性更好(元素名、属性名均支持中文),很受开发者青睐。为帮助初学者快速掌握Delphi中的XML编程,笔者特写此文,以供交流。
笔者通过一个读写XML文件的实例来说明XML编程的各个步骤,只需读者有结点、元素、属性的基本概念就能容易的理解本文。笔者所要读入的XML文件结构如下所示,命名为Input.xml。
<学生花名册>
<学生 性别 = "男">
<姓名>李华
<年龄>14
<电话>6287555
<学生 性别 = "男">
<姓名>张三
<年龄>16
<电话>8273425
Input.xml文件的第一行是XML的版本说明,属性encoding宣告使用何种字符集建立,默认以Unicode 编码(UTF-8 或UTF-16),这里用中文GB2312码。第二行“<学生花名册>“是根元素。下面定义了两个学生元素,学生下面嵌套了三个子元素,是对学生的进一步说明。与之相对应的,我们在Delphi中定义如下的学生数据结构,"//"后面的文字是对变量或语句的说明,下同。
TStudent = class {学生}
sex : string; //学生性别
name : string; //学生姓名
age : integer; //学生年龄
phone: string; //电话号码
end;
为了读写,我们需要放置两个TXMLDocument控件,在Delphi VCL面板的Internet标签页里那个标有XML字样的控件就是,当然此控件也可以动态创建,但需要包含必要的文件,这里为简单起见,我们直接放置在窗体上,分别命名为InXMLDoc和OutXMLDoc,InXMLDoc用于调入Input.xml文件,OutXMLDoc用于暂存输出到Output.xml的文档。
在窗体上放个按钮,我们把测试代码直接放置在按钮的单击事件里。先定义几个变量,用来保存临时信息,如下所示:
Root : IXMLNode; //指向XML根结点
Parent_Node: IXMLNode; //指向学生结点
Child_node : IXMLNode; //指向学生的子结点
Student : TStudent; //存单个学生信息
List : TList; //存学生列表
i : integer; //循环变量
我们先来读入XML文件,代码如下:
List := TList.Create; //初始化列表
InXMLDoc.LoadFromFile('Input.xml'); //调入Input.xml文件
Root := InXMLDoc.DocumentElement; //取XML文件的根结点,即“<学生花名册>”
Parent_Node := Root.ChildNodes.First; //使Parent_Node指向学生结点
while (Parent_Node <> nil) do //循环取多个学生,可再多加几个学生信息测试
begin
if (Parent_Node.NodeName = '学生') then //判断是否为学生结点
begin
Student := TStudent.Create; //新建一个学生的结构信息
Student.sex := Parent_Node.Attributes['性别']; //取学生的性别属性
Child_Node := Parent_Node.ChildNodes.First;
//使Child_Node指向该学生的第一个子结点信息
while (Child_Node <> nil) do //循环取学生的各个子各点
begin
if (Child_Node.NodeName = '姓名') then //判断是否为姓名结点
Student.name := Child_Node.Text //取姓名结点的值,取于name字段中
else if (Child_Node.NodeName = '年龄') then //此行起后四行与前两行类似
Student.age := StrToInt(Child_Node.Text)
else if (Child_Node.NodeName = '电话') then
Student.phone := Child_Node.Text;
Child_Node := Child_Node.NextSibling; //顺序取下一个学生的子结点信息
end;
List.Add(Student); //把一个学生信息加入列表
end;
Parent_Node := Parent_Node.NextSibling; //顺序取下一个学生信息
end;
到这儿,所有的学生信息都已存到List列表里面了,读者可以跟踪代码测试。
下面我们把List里的临时学生信息存到Output.xml文件里,代码如下:
OutXMLDoc.Active := true; //激活OutXMLDoc,自动初始化空的XML文档
OutXMLDoc.Encoding := 'GB2312'; //设置字符集
Root := OutXMLDoc.AddChild('学生花名册'); //建根结点
for i := 0 to List.Count - 1 do //循环取各个学生信息
begin
Student := List.Items[i]; //顺序取一个学生信息
if (Student <> nil) then
begin
Parent_Node := Root.AddChild('学生'); //根结点后添加一个学生结点
Parent_Node.Attributes['性别'] := Student.sex; //给学生结点设置性别属性
Child_Node := Parent_Node.AddChild('姓名'); //学生结点后添加一个姓名结点
Child_Node.Text := Student.name; //设置姓名的文本值
Child_Node := Parent_Node.AddChild('年龄'); //此行起后四行与前两行类似
Child_Node.Text := IntToStr(Student.age);
Child_Node := Parent_Node.AddChild('电话');
Child_Node.Text := Student.phone;
end;
end;
OutXMLDoc.SaveToFile('Output.xml'); //把组织好的XML文档存于Output.xml文件中
OutXMLDoc.Active := false; //钝化(关闭)OutXMLDoc
List.Free; //最后释放保存临时学生信息的列表
{
public:
__fastcall TJJXMLDocument(TXMLDocument* XMLDoc,
String Software,
String Method,
int DocumentVersion);
__fastcall ~TJJXMLDocument();
protected:
bool m_Connected;
TXMLDocument* m_XMLDoc;
String m_Software; // 软件名称
String m_Method; // 最高祖先节点
int m_DocumentVersion;
private:
virtual bool __fastcall Encode()=0;
virtual bool __fastcall Decode()=0;
public:
bool __fastcall SaveToFile(TFileName FileName); // 保存
bool __fastcall LoadFromFile(TFileName FileName); // 读取
};
//---------------------------------------------------------------------------
__fastcall TJJXMLDocument::TJJXMLDocument(TXMLDocument* XMLDoc,
String Software,
String Method,
int DocumentVersion)
: m_XMLDoc(XMLDoc),
m_Software(Software),
m_Method(Method),
m_DocumentVersion(DocumentVersion)
{
}
//---------------------------------------------------------------------------
__fastcall TJJXMLDocument::~TJJXMLDocument()
{
m_XMLDoc = NULL;
}
//---------------------------------------------------------------------------
bool __fastcall TJJXMLDocument::SaveToFile(TFileName FileName) // 保存
{
bool Result = false;
try {
if ( Encode() )
{
m_XMLDoc->SaveToFile(FileName);
Result = true;
}
}catch(...){
}
return Result;
}
//---------------------------------------------------------------------------
bool __fastcall TJJXMLDocument::LoadFromFile(TFileName FileName) // 读取
{
bool Result = false;
try {
m_XMLDoc->LoadFromFile(FileName);
Result = Decode();
}catch(...){
}
return Result;
}
// ========================================================================================================
// ========================================================================================================
// ========================================================================================================
// ========================================================================================================
class TXMLOnlineUpdate : public TJJXMLDocument
{
public:
__fastcall TXMLOnlineUpdate(TXMLDocument* XMLDoc, String Software);
__fastcall ~TXMLOnlineUpdate();
public: // 信息清单
void __fastcall Init(); // 被成员变量进行初始化,同时在读信息失败时的原始化恢复
// === (淘汰的发布版本) ==============================================================================
// WashOut
int wso_WashOutVersion; // 已被淘汰的版本号 - WashOutVersion
// === (正式的发布版本) ==============================================================================
// Release
String rls_VersionString; // 完整版本号字符串 - VersionString
int rls_ExecuteFileVersion; // 可执行文件版本号 - ExecuteFileVersion
int rls_DatabaseFileVersion; // 数据库文件版本号 - DatabaseFileVersion
String rls_ExecuteFileURL; // 文件下载 URL - ExecuteFileURL
String rls_EXEFileName; // 可执行文件名
String rls_DatabaseFileURL; // 文件下载 URL - DatabaseFileURL
String rls_DBFFileName; // 数据库文件名
String rls_PackageDownloadURL; // 完整软件包下载 URL - PackageDownloadURL
// === (最新的测试版本) ==============================================================================
// Debug
String dbg_VersionString; // 完整版本号字符串 - VersionString
int dbg_ExecuteFileVersion; // 可执行文件版本号 - ExecuteFileVersion
int dbg_DatabaseFileVersion; // 数据库文件版本号 - DatabaseFileVersion
String dbg_ExecuteFileURL; // 文件下载 URL - ExecuteFileURL
String dbg_EXEFileName; // 可执行文件名
String dbg_DatabaseFileURL; // 文件下载 URL - DatabaseFileURL
String dbg_DBFFileName; // 数据库文件名
String dbg_PackageDownloadURL; // 完整软件包下载 URL - PackageDownloadURL
private:
virtual bool __fastcall Decode(); // 从 XML 中解码
virtual bool __fastcall Encode(); // 编码写入 XML
public:
bool __fastcall JudgeEXEVersion(int CurrentEXEVersion); // 确定是否需要升级
bool __fastcall JudgeDBFVersion(int CurrentDBFVersion); // 确定是否需要升级
bool __fastcall JudgeAlphaStageProducts_EXE(int CurrentEXEVersion); // 确定是否存在更新的测试版
bool __fastcall JudgeAlphaStageProducts_DBF(int CurrentDBFVersion); // 确定是否存在更新的测试版
};
__fastcall TXMLOnlineUpdate::TXMLOnlineUpdate(TXMLDocument* XMLDoc, String Software)
: TJJXMLDocument(XMLDoc, Software, "OnlineUpdate", 1)
{
Init();
}
//---------------------------------------------------------------------------
__fastcall TXMLOnlineUpdate::~TXMLOnlineUpdate()
{
}
//---------------------------------------------------------------------------
void __fastcall TXMLOnlineUpdate::Init() // 被成员变量进行初始化,同时在读信息失败时的原始化恢复
{
// === (淘汰的发布版本) ==============================================================================
// WashOut
wso_WashOutVersion = 0; // 已被淘汰的版本号 - WashOutVersion
// === (正式的发布版本) ==============================================================================
// Release
rls_VersionString = "0.0.0.0"; // 完整版本号字符串 - VersionString
rls_ExecuteFileVersion = 0; // 可执行文件版本号 - ExecuteFileVersion
rls_DatabaseFileVersion = 0; // 数据库文件版本号 - DatabaseFileVersion
rls_ExecuteFileURL = ""; // 文件下载 URL - ExecuteFileURL
rls_EXEFileName = "";
rls_DatabaseFileURL = ""; // 文件下载 URL - DatabaseFileURL
rls_DBFFileName = "";
rls_PackageDownloadURL = ""; // 完整软件包下载 URL - PackageDownloadURL
// === (最新的测试版本) ==============================================================================
// Debug
dbg_VersionString = "0.0.0.0"; // 完整版本号字符串 - VersionString
dbg_ExecuteFileVersion = 0; // 可执行文件版本号 - ExecuteFileVersion
dbg_DatabaseFileVersion = 0; // 数据库文件版本号 - DatabaseFileVersion
dbg_ExecuteFileURL = ""; // 文件下载 URL - ExecuteFileURL
dbg_EXEFileName = "";
dbg_DatabaseFileURL = ""; // 文件下载 URL - DatabaseFileURL
dbg_DBFFileName = "";
dbg_PackageDownloadURL = ""; // 完整软件包下载 URL - PackageDownloadURL
}
//---------------------------------------------------------------------------
bool __fastcall TXMLOnlineUpdate::Decode()
{
if ( ! m_XMLDoc->Active )
{
try {
m_XMLDoc->Active = true;
}catch(...){
return false;
}
}
Init();
_di_IXMLNode NodeSoftware;
_di_IXMLNode NodeWashOut;
_di_IXMLNode NodeVersion;
_di_IXMLNode NodeDebug;
_di_IXMLNode Node;
NodeSoftware = m_XMLDoc->ChildNodes->FindNode(m_Software);
if ( NodeSoftware )
{
String s;
s = NodeSoftware->GetAttribute("Method");
if ( s == "OnlineUpdate" )
{
m_Method = s;
s = NodeWashOut->GetAttribute("Version");
if ( m_DocumentVersion >= s.ToIntDef(0) );
{
m_DocumentVersion = s.ToIntDef(0);
NodeWashOut = NodeSoftware->ChildNodes->FindNode("WashOut");
if ( NodeWashOut )
{
s = NodeWashOut->GetAttribute("Version");
wso_WashOutVersion = s.ToIntDef(0);
}
NodeVersion = NodeSoftware->ChildNodes->FindNode("Release");
if ( NodeVersion )
{
rls_VersionString = NodeVersion->GetAttribute("Version");
Node = NodeVersion->ChildNodes->FindNode("ExecuteFile");
if ( Node )
{
rls_ExecuteFileVersion = Node->GetAttribute("Version" );
rls_ExecuteFileURL = Node->GetAttribute("URL" );
rls_EXEFileName = Node->GetAttribute("FileName");
}
Node = NodeVersion->ChildNodes->FindNode("DatabaseFile");
if ( Node )
{
rls_DatabaseFileVersion = Node->GetAttribute("Version" );
rls_DatabaseFileURL = Node->GetAttribute("URL" );
rls_DBFFileName = Node->GetAttribute("FileName");
}
}
NodeVersion = NodeSoftware->ChildNodes->FindNode("Debug");
if ( NodeVersion )
{
dbg_VersionString = NodeVersion->GetAttribute("Version");
Node = NodeVersion->ChildNodes->FindNode("ExecuteFile");
if ( Node )
{
dbg_ExecuteFileVersion = Node->GetAttribute("Version" );
dbg_ExecuteFileURL = Node->GetAttribute("URL" );
dbg_EXEFileName = Node->GetAttribute("FileName");
}
Node = NodeVersion->ChildNodes->FindNode("DatabaseFile");
if ( Node )
{
dbg_DatabaseFileVersion = Node->GetAttribute("Version" );
dbg_DatabaseFileURL = Node->GetAttribute("URL" );
dbg_DBFFileName = Node->GetAttribute("FileName");
}
}
}
}
m_XMLDoc->Active = false;
return true;
}
//---------------------------------------------------------------------------
bool __fastcall TXMLOnlineUpdate::Encode()
{
m_XMLDoc->LoadFromXML(WideString(""));
m_XMLDoc->Active = true;
m_XMLDoc->ChildNodes->Clear();
m_XMLDoc->StandAlone = "yes";
_di_IXMLNode NodeSoftware;
_di_IXMLNode NodeWashOut;
_di_IXMLNode NodeRelease;
_di_IXMLNode NodeDebug;
_di_IXMLNode Node;
// ===================================================================================================
// NodeAncestor = m_XMLDoc->CreateNode(m_Ancestor, ntElement, "FriendSafe");
NodeSoftware = m_XMLDoc->CreateNode(m_Software);
NodeSoftware->SetAttribute("Method", m_Method);
NodeSoftware->SetAttribute("Version", m_DocumentVersion);
m_XMLDoc->ChildNodes->Add(NodeSoftware);
// ===================================================================================================
NodeWashOut = NodeSoftware->AddChild("WashOut");
NodeWashOut->SetAttribute("Version", wso_WashOutVersion);
// ===================================================================================================
NodeRelease = NodeSoftware->AddChild("Release");
NodeRelease->SetAttribute("Version", rls_VersionString);
// NodeRelease->SetText(rls_ExecuteFileURL);
Node = NodeRelease->AddChild("ExecuteFile");
Node->SetAttribute("Version", rls_ExecuteFileVersion);
Node->SetAttribute("URL", rls_ExecuteFileURL);
Node->SetAttribute("FileName", rls_EXEFileName);
Node = NodeRelease->AddChild("DatabaseFile");
Node->SetAttribute("Version", rls_DatabaseFileVersion);
Node->SetAttribute("URL", rls_DatabaseFileURL);
Node->SetAttribute("FileName", rls_DBFFileName);
// ===================================================================================================
NodeDebug = NodeSoftware->AddChild("Debug");
NodeDebug ->SetAttribute("Version", dbg_VersionString);
// NodeDebug ->SetText(dbg_DatabaseFileURL);
Node = NodeDebug->AddChild("ExecuteFile");
Node->SetAttribute("Version", dbg_ExecuteFileVersion);
Node->SetAttribute("URL", dbg_ExecuteFileURL);
Node->SetAttribute("FileName", dbg_EXEFileName);
Node = NodeDebug->AddChild("DatabaseFile");
Node->SetAttribute("Version", dbg_DatabaseFileVersion);
Node->SetAttribute("URL", dbg_DatabaseFileURL);
Node->SetAttribute("FileName", dbg_DBFFileName);
return true;
}
//---------------------------------------------------------------------------
bool __fastcall TXMLOnlineUpdate::JudgeEXEVersion(int CurrentEXEVersion) // 确定是否需要升级
{
return false;
}
//---------------------------------------------------------------------------
bool __fastcall TXMLOnlineUpdate::JudgeDBFVersion(int CurrentDBFVersion) // 确定是否需要升级
{
return false;
}