You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:42:05