Search code examples
xmldelphi

Parsing a XML file in Delphi using IXMLDocument


I am attempting to parse this XML file in a Delphi 11.3 (VCL app) using IXMLDocument. I am traversing the tree properly, but I'm not able to extract the values from within the jobbean node. Ideally, I'd like to populate some values into a stringgrid, but for now, I'm just adding them to a TMemo object.

Currently, my XMLMemo object is just being populated with the value of 'j' and the string 'item'. I'd like to grab the item name and the associated value. For example, the string "JobID" and its value "1664-b6b2-ac13-876020240304112009", then "JobVersion" and its value "3.6", and so on.

Here's the XML (stored in FileName) I'm working with:

<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>
 

Here is my Delphi code:

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; 

Right now the output looks like:

0 item
1 item
2 item
3 item
4 item
5 item
6 item
7 item
8 item
0 item
1 item
...

How do I extract out of this XML file the values that I need?


Solution

  • The values you are looking for are attributes of the <item> nodes, but you are not accessing any attributes. Use the IXMLNode.AttributeNodes or IXMLNode.Attributes[] property to access them, eg:

    for j := 0 to JobBeanNode.ChildNodes.Count - 1 do
    begin
      ChildNode := JobBeanNode.ChildNodes[i];
    
      name := ChildNode.Attributes['name'];
      value := ChildNode.Attributes['value'];
      //...
    
      // alternatively:
    
      for k := 0 to ChildNode.AttributeNodes.Count - 1 do
      begin
        AttrNode := ChildNode.AttributeNodes[k];
        name := AttrNode.NodeName;
        value := AttrNode.NodeValue;
        //...
      end;
    end;
    

    On a side note - you can replace these 3 lines:

    XMLDoc := TXMLDocument.Create(nil);
    XMLDoc.LoadFromFile(FileName);
    XMLDoc.Active := True;
    

    With 1 line by using the LoadXMLDocument() function:

    XMLDoc := LoadXMLDocument(FileName);