Delphi 11.3中使用IXMLDocument解析XML提取jobbean节点数据问题
Delphi 11.3 VCL中提取XML节点属性值的问题
在Delphi 11.3的VCL应用中使用IXMLDocument解析XML文件时,能正常遍历节点树,但无法提取jobbean节点内item元素的name和value属性值。目前尝试将数据输出到TMemo,但仅能输出循环变量j的数值和item节点名,需要获取如JobID及其对应值1664-b6b2-ac13-876020240304112009这类属性对,最终目标是将数据填充到TStringGrid。
待解析的XML文件
<root> <joblist> <jobbean> <item name="JobID" value="1664-b6b2-ac13-876020240304112009"/> <item name="JobVersion" value="3.6"/> <item name="JobName" value="14509-20240304"/> <item name="JobState" value="3"/> <item name="JobStatus" value="2"/> <item name="CreationDate" value="638451660887232507"/> <item name="ModifyTime" value="638451663423079957"/> <item name="Priority" value="1"/> <item name="Operator" value=""/> </jobbean> <jobbean> <item name="JobID" value="1664-b6b2-ac13-876020240304112547"/> <item name="JobVersion" value="3.6"/> <item name="JobName" value="14509-20240304"/> <item name="JobState" value="3"/> <item name="JobStatus" value="2"/> <item name="CreationDate" value="638451660887232507"/> <item name="ModifyTime" value="638451663423079957"/> <item name="Priority" value="1"/> <item name="Operator" value=""/> </jobbean> <jobbean> <item name="JobID" value="1664-b6b2-ac13-876020240304173521"/> <item name="JobVersion" value="3.6"/> <item name="JobName" value="AC-7BAD0QHO20240304173528"/> <item name="JobState" value="4"/> <item name="JobStatus" value="5"/> <item name="CreationDate" value="638451885369544727"/> <item name="ModifyTime" value="638451885369560248"/> <item name="Priority" value="1"/> <item name="Operator" value=""/> </jobbean> </joblist> </root>
当前使用的Delphi代码
procedure Tfrm_Main.btn_XMLClick(Sender: TObject); begin ReadXMLFile(FileName); end; procedure Tfrm_Main.ReadXMLFile(const FileName: string); var XMLDoc: IXMLDocument; RootNode, JobListNode, JobBeanNode, ChildNode: IXMLNode; NodeList: IXMLNodeList; i, j: Integer; begin XMLDoc := TXMLDocument.Create(nil); try XMLDoc.LoadFromFile(FileName); XMLDoc.Active := True; RootNode := XMLDoc.DocumentElement; if Assigned(RootNode) then begin // Access node properties JobListNode := RootNode.ChildNodes.FindNode('joblist'); if Assigned(JobListNode) then begin for i := 0 to JobListNode.ChildNodes.Count - 1 do begin JobBeanNode := JobListNode.ChildNodes[i]; if Assigned(JobBeanNode) then begin for j := 0 to JobBeanNode.ChildNodes.Count - 1 do begin ChildNode := JobBeanNode.ChildNodes[i]; if Assigned(ChildNode) then begin XMLMemo.Lines.Add(IntToStr(j) + ' ' + ChildNode.NodeName); end; end; end; end; end; end; finally XMLDoc := nil; end; end;
当前输出结果
0 item 1 item 2 item 3 item 4 item 5 item 6 item 7 item 8 item 0 item 1 item ...
解决方案
1. 修正循环变量错误
代码内层循环存在笔误:ChildNode := JobBeanNode.ChildNodes[i]; 误用了外层循环变量i,应改为内层循环变量j,否则每次都会取jobbean下的第i个item节点,而非当前循环的第j个。
2. 提取节点属性值
要获取item节点的name和value属性,可通过IXMLNode.Attributes属性直接访问,语法为Node.Attributes['属性名']。
修改后的Memo输出代码
procedure Tfrm_Main.ReadXMLFile(const FileName: string); var XMLDoc: IXMLDocument; RootNode, JobListNode, JobBeanNode, ChildNode: IXMLNode; i, j: Integer; AttrName, AttrValue: string; begin XMLDoc := TXMLDocument.Create(nil); try XMLDoc.LoadFromFile(FileName); XMLDoc.Active := True; RootNode := XMLDoc.DocumentElement; if Assigned(RootNode) then begin JobListNode := RootNode.ChildNodes.FindNode('joblist'); if Assigned(JobListNode) then begin // 清空Memo内容 XMLMemo.Clear; for i := 0 to JobListNode.ChildNodes.Count - 1 do begin JobBeanNode := JobListNode.ChildNodes[i]; if Assigned(JobBeanNode) then begin // 标记当前jobbean XMLMemo.Lines.Add('=== JobBean ' + IntToStr(i+1) + ' ==='); for j := 0 to JobBeanNode.ChildNodes.Count - 1 do begin // 修正循环变量为j ChildNode := JobBeanNode.ChildNodes[j]; if Assigned(ChildNode) then begin // 获取属性值 AttrName := ChildNode.Attributes['name']; AttrValue := ChildNode.Attributes['value']; // 输出到Memo XMLMemo.Lines.Add(Format('%s: %s', [AttrName, AttrValue])); end; end; XMLMemo.Lines.Add(''); // 空行分隔不同jobbean end; end; end; end; finally XMLDoc := nil; end; end;
3. 填充到TStringGrid的示例
如果要将数据填充到TStringGrid,可先设置表头再逐行添加数据:
procedure Tfrm_Main.FillStringGridFromXML(const FileName: string); var XMLDoc: IXMLDocument; RootNode, JobListNode, JobBeanNode, ChildNode: IXMLNode; i, j, RowIdx: Integer; begin XMLDoc := TXMLDocument.Create(nil); try XMLDoc.LoadFromFile(FileName); XMLDoc.Active := True; RootNode := XMLDoc.DocumentElement; if Assigned(RootNode) then begin JobListNode := RootNode.ChildNodes.FindNode('joblist'); if Assigned(JobListNode) then begin // 设置StringGrid列数 StringGrid1.ColCount := 9; // 设置表头 StringGrid1.Cells[0, 0] := 'JobID'; StringGrid1.Cells[1, 0] := 'JobVersion'; StringGrid1.Cells[2, 0] := 'JobName'; StringGrid1.Cells[3, 0] := 'JobState'; StringGrid1.Cells[4, 0] := 'JobStatus'; StringGrid1.Cells[5, 0] := 'CreationDate'; StringGrid1.Cells[6, 0] := 'ModifyTime'; StringGrid1.Cells[7, 0] := 'Priority'; StringGrid1.Cells[8, 0] := 'Operator'; RowIdx := 1; for i := 0 to JobListNode.ChildNodes.Count - 1 do begin JobBeanNode := JobListNode.ChildNodes[i]; if Assigned(JobBeanNode) then begin StringGrid1.RowCount := RowIdx + 1; for j := 0 to JobBeanNode.ChildNodes.Count - 1 do begin ChildNode := JobBeanNode.ChildNodes[j]; if Assigned(ChildNode) then begin // 根据item顺序匹配列 case j of 0: StringGrid1.Cells[0, RowIdx] := ChildNode.Attributes['value']; 1: StringGrid1.Cells[1, RowIdx] := ChildNode.Attributes['value']; 2: StringGrid1.Cells[2, RowIdx] := ChildNode.Attributes['value']; 3: StringGrid1.Cells[3, RowIdx] := ChildNode.Attributes['value']; 4: StringGrid1.Cells[4, RowIdx] := ChildNode.Attributes['value']; 5: StringGrid1.Cells[5, RowIdx] := ChildNode.Attributes['value']; 6: StringGrid1.Cells[6, RowIdx] := ChildNode.Attributes['value']; 7: StringGrid1.Cells[7, RowIdx] := ChildNode.Attributes['value']; 8: StringGrid1.Cells[8, RowIdx] := ChildNode.Attributes['value']; end; end; end; Inc(RowIdx); end; end; end; end; finally XMLDoc := nil; end; end;
内容的提问来源于stack exchange,提问作者Hackbrew
相关产品推荐
相关产品推荐

