Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use query on XML file in Delphi?

Tags:

xml

delphi

I am new in Delphi, and here is the thing I want to do. I have XML file formated like this,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Row>
        <Designation>1234102</Designation>
        <Inner>5.412</Inner>
        <Outer>3.588</Outer>
        <Spin>4.732</Spin>
        <Cage>0.399</Cage>
    </Row>
    <Row>
        <Designation>1342153</Designation>
        <Inner>5.916</Inner>
        <Outer>4.084</Outer>
        <Spin>5.277</Spin>
        <Cage>0.408</Cage>
    </Row>
    ........
</Data>

and I want to query it with Delphi. For example: I want data of where is 1342153. What is the best and easiest solution?

Thank in advance for example and explanation.

like image 983
user2572823 Avatar asked Mar 23 '23 05:03

user2572823


2 Answers

I'm going to make the presumption that once you find the Designation, you're going to want to also read the other entries (Inner, Outer, Spin, and Cage) that go with the designation.

XPath is the perfect solution for this problem. My example uses a new form with just a TMemo and TButton dropped on it, and adding a handler for the Button1.OnClick event:

uses
  MSXML, ComObj, ActiveX;

const
  XMLText =  '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
             '<Data>' +
              '<Row>' +
                  '<Designation>1234102</Designation>' +
                  '<Inner>5.412</Inner>' +
                  '<Outer>3.588</Outer>' +
                  '<Spin>4.732</Spin>' +
                  '<Cage>0.399</Cage>' +
              '</Row>' +
              '<Row>' +
                 '<Designation>1342153</Designation>' +
                 '<Inner>5.916</Inner>' +
                  '<Outer>4.084</Outer>' +
                  '<Spin>5.277</Spin>' +
                  '<Cage>0.408</Cage>' +
              '</Row>' +
          '</Data>';

procedure TForm1.Button1Click(Sender: TObject);
var
  XMLDoc: IXMLDOMDocument;
  Node, SibNode: IXMLDOMNode;
begin
  Memo1.Clear;
  XMLDoc := CoDOMDocument.Create;
  XMLDoc.loadXML(XMLText);

  // Select the node with the Designation you want.
  Node := XMLDoc.selectSingleNode('//Designation[text()="1342153"]');
  if Assigned(Node) then
  begin
    Memo1.Lines.Add('Found it.');
    Memo1.Lines.Add(Node.nodeName + ' = ' + Node.firstChild.nodeValue);

    // Read all the nodes at the same level as the Designation
    SibNode := Node.nextSibling;
    while SibNode <> nil do
    begin
      Memo1.Lines.Add(SibNode.nodeName + ' = ' + 
                      SibNode.firstChild.nodeValue);
      Sib := Sib.nextSibling;
    end;
  end;
end;

If you want to just grab all of the <Row> elements, and loop through the information they contain, you can use this (add a second button to the test app above, and use this for the Button2.OnClick handler):

procedure TForm1.Button2Click(Sender: TObject);
var
  XMLDoc: IXMLDOMDocument;
  NodeList: IXMLDOMNodeList;
  Node, SibNode: IXMLDOMNode;
  i: Integer;
begin
  Memo1.Clear;
  XMLDoc := CoDOMDocument.Create;
  XMLDoc.loadXML(XMLText);
  NodeList := XMLDoc.selectNodes('/Data/Row');
  if Assigned(NodeList) then
  begin
    for i := 0 to NodeList.length - 1 do
    begin
      Node := NodeList.item[i];
      SibNode := Node.firstChild;
      while Assigned(SibNode) do
      begin
        Memo1.Lines.Add(SibNode.nodeName + ' = ' + 
                        SibNode.firstChild.nodeValue);
        SibNode := SibNode.nextSibling;
      end;
    end;
    // Add a blank line between groupings for readability
    Memo1.Lines.Add('');
  end;
end;
like image 115
Ken White Avatar answered Apr 02 '23 20:04

Ken White


As others suggested you can use XPath to find a particular value, in this case using this expression /Data/Row/Designation[text()="1342153"] will locate the node which contains the value 1342153 in the Designation.

Try this sample code

{$APPTYPE CONSOLE}

{$R *.res}

uses
  MSXML,
  SysUtils,
  ActiveX,
  ComObj;

Const
 XmlStr =
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
'<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'+
'    <Row>'+
'        <Designation>1234102</Designation>'+
'        <Inner>5.412</Inner>'+
'        <Outer>3.588</Outer>'+
'        <Spin>4.732</Spin>'+
'        <Cage>0.399</Cage>'+
'    </Row>'+
'    <Row>'+
'        <Designation>1342153</Designation>'+
'        <Inner>5.916</Inner>'+
'        <Outer>4.084</Outer>'+
'        <Spin>5.277</Spin>'+
'        <Cage>0.408</Cage>'+
'    </Row>'+
'</Data>';

procedure Test;
Var
  XMLDOMDocument  : IXMLDOMDocument;
  XMLDOMNode      : IXMLDOMNode;
begin
  XMLDOMDocument:=CoDOMDocument.Create;
  XMLDOMDocument.loadXML(XmlStr);
  XMLDOMNode := XMLDOMDocument.selectSingleNode('/Data/Row/Designation[text()="1342153"]');
  if XMLDOMNode<>nil then
   Writeln('Found');
end;

begin
 try
    CoInitialize(nil);
    try
      Test;
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.
like image 31
RRUZ Avatar answered Apr 02 '23 19:04

RRUZ