這個程序可以用於解析任何合法的XML字符串。
首先是看一下程序的運行效果:
以解析這樣一個XML的字符串為例:
<?xml version="1.0" encoding="UTF-8"?><BookInfo><Owner><OwnerName>張三</OwnerName><OwnerAge>1234</OwnerAge></Owner><BookMes><BookName>時間簡史</BookName><ISDN>234343453534</ISDN><Writer>霍金</Writer></BookMes></BookInfo>
首先是打開應用程序

然后將上面所示的字符串復制到文本編輯框中,然后點擊解析按鈕,會出現下面的效果

如上圖所示,可以 “XML中的字段標簽:XML中對應標簽的值” 的格式顯示解析的效果。
因為進行了異常處理(使用try..except..end,並且在異常處理中使用ShowMessage彈出異常信息),所以如果輸入的字符串不是合法的XML格式的話,程序會正常報錯,而不會異常終止。
比如沒有輸入直接點擊解析按鈕,效果如下:

有比如輸入一個非法的字符串,效果如下

然后看一下代碼
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, XMLIntf, XMLDoc;
type
TForm1 = class(TForm)
edt1: TEdit;
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure ReadXml(Node: IXMLNode; var showmess: string);
var
NodeList: IXMLNodeList;
strName: string;
i: Integer;
begin
if not Node.HasChildNodes then Exit;
nodeList := node.ChildNodes;
for i := 0 to nodeList.Count - 1 do
begin
strName := nodeList[i].NodeName;
if nodeList[i].IsTextElement then //如果是元素
begin
showmess:= showmess + strName + ':' + NodeList[i].NodeValue + #13#10;
end
else if nodeList[i].HasChildNodes then //如果有子節點
begin
ReadXml(NodeList[i], showmess);
end;
end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
sXML, showmess: string;
ComInstrXML: IXMLDocument;
mainNode: IXMLNode;
begin
showmess:= '';
sXML:= edt1.Text;
sXML:= StringReplace(sXML, 'UTF-8', 'gbk', []); //只替換<?xml version="1.0" encoding="UTF-8"?>里面的字符編碼方式,因為往往這個是在最前面出現的,所以StringReplace的第四個參數是[]
try //一定不要忘記異常處理,保證程序的穩定性,能夠正常處理異常而不至於在發生異常的時候導致程序崩潰
ComInstrXML:= LoadXMLData(sXML);
mainNode:= ComInstrXML.DocumentElement;
readXML(mainNode, showmess);
ShowMessage(showmess);
except
on E: Exception do
begin
ShowMessage(E.Message);
end;
end;
end;
end.
講解一下代碼
0.建議這樣使用XML解包
本例中的程序,在解包之后是將標簽以及對應的值顯示在彈出框上,這樣只是為了演示解析XML的效果。
建議在開發中將解析好的XML節點,以節點的標簽作為Key,以節點的內容作為value,插入到一個可以搜索的鏈表或者其他什么可以根據Key進行搜索的容器類中,然后在之后使用的時候就可以很方便的搜索到解析后的值。
1.注意解析XML使用到相關的類、方法所屬的單元
要使用IXMLDocument、IXMLNodeList和iXMLNode,需要引入 XMLIntf 單元。
要使用 LoadXMLData方法,需要引入XMLDoc 單元。
2.遞歸解包XML
因為XML本身就是一個遞歸的結構,所以解包XML,也就是其中的ReadXML 方法使用的就是遞歸的方法,遞歸結束標志是:正在解析的XML標簽是一個元素,沒有子節點。
3.字符編碼的問題
在 TForm1.btn1Click(Sender: TObject) 方法中,我們可以看到首先將XML字符串中的 'UTF-8' 替換為 'gbk',因為如果編碼方式是UTF-8:<?xml version="1.0" encoding="UTF-8"?>,那么如果XML中存在中文,那么解析的時候會報錯(如果全部為英文,那么就不會報錯),如下圖

如果將UTF-8替換為gbk,,那么在解析XML的時候就不會報這樣的錯誤。
另外如果以不包含編碼格式的XML字符串,如:<BookInfo><Owner><OwnerName>張三</OwnerName><OwnerAge>1234</OwnerAge></Owner><BookMes><BookName>時間簡史</BookName><ISDN>234343453534</ISDN><Writer>霍金</Writer></BookMes></BookInfo>,沒有 <?xml version="1.0" encoding="UTF-8"?>的話,此時就算有 sXML:= StringReplace(sXML, 'UTF-8', 'gbk', [rfReplaceAll]); 這樣的替換字符編碼的代碼也是沒有用的,也沒有辦法改成gbk的編碼,所以仍然會報上面的異常。
所以請注意字符編碼的問題,尤其是既有中文又有英文的時候。
另外還有一個需要注意的點,我們只需要替換“<?xml version="1.0" encoding="UTF-8"?>”這個里面的UTF-8為gbk就行了,因為可能XML本身的其他字段就存儲着什么關於字符編碼的信息,但是與本條XML報文無關,純粹只是一條需要傳輸的信息。下面的一條XML的報文就是例子:
<?xml version="1.0" encoding="UTF-8"?><BookInfo><Charset>UTF-8</Charset><Owner><OwnerName>張三</OwnerName><OwnerAge>1234</OwnerAge></Owner><BookMes><BookName>時間簡史</BookName><ISDN>234343453534</ISDN><Writer>霍金</Writer></BookMes></BookInfo>
這時候在替換的時候,要注意只要替換XML本身的字符編碼就好了,其他的XML需要傳輸的可能有關於字符編碼的信息不能替換,否則可能導致傳輸的XML信息違背了其傳輸時候的初衷了!!
所以上面的代碼中使用:sXML:= StringReplace(sXML, 'UTF-8', 'gbk', []); 其中StringReplace的第四個參數是[] 表示只替換第一個即可。
4.stringReplace函數的使用
function StringReplace (const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
rfReplaceAll:全部替換
rfIgnoreCase:忽略大小寫
例子
var
aStr: String;
begin
aStr := 'This is a book, not a pen!';
ShowMessage(StringReplace (aStr, 'a', 'two', []));//This is two book, not a pen!只替換了第一個符合的字符串
ShowMessage(StringReplace (aStr, 'a', 'two', [rfReplaceAll]));//This is two book, not two pen!替換了所有符合的字符串
aStr := 'This is a book, not A pen!';
ShowMessage(StringReplace (aStr, 'a', 'two', [rfReplaceAll]));//This is two book, not A pen!只替換了符合的字符串(小寫a)
ShowMessage(StringReplace (aStr, 'a', 'two', [rfReplaceAll, rfIgnoreCase]));//This is two book, not two pen!不管大小寫替換了所有符合的字符串
end;
5.換行
注意代碼中有這樣一行代碼:
showmess:= showmess + strName + ':' + NodeList[i].NodeValue + #13#10;
其中的 #13#10 表示換行
