4

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.

user2572823
  • 53
  • 1
  • 1
  • 5
  • what do you mean by query ? why do you need that value and not the others ? will you ever want the other values too? which of them and why and how frequently ? there may be several solutions like DOM-parsers, SAX-parsers, XPATH, records-array de-serialization - but it is not known what actually you do need to do with XML. http://catb.org/esr/faqs/smart-questions.html – Arioch 'The Jul 11 '13 at 13:41
  • also edit your question please and below the text add the TAG with your specific delphi language version – Arioch 'The Jul 11 '13 at 13:42
  • My XML has around 6000 "rows" and I would like to read whole row not just designation. – user2572823 Jul 12 '13 at 06:05

4 Answers4

3

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.
RRUZ
  • 134,889
  • 20
  • 356
  • 483
3

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;
Ken White
  • 123,280
  • 14
  • 225
  • 444
1

IXMLDocument and XPath are your friends when querying xml in Delphi you can find many sources for that, e.g. XPath and TXmlDocument

Community
  • 1
  • 1
fuchs777
  • 993
  • 1
  • 14
  • 30
0

As you want to query the data from xml I recommend that you use the XML Transformation documented here http://docwiki.embarcadero.com/RADStudio/XE4/en/Converting_XML_Documents_into_Data_Packets

This will map you xml to a ClientDataSet the you can filter the records by the collumns you want or you can use DataBinding Wizard it has the explanation in the docs at this url http://docwiki.embarcadero.com/RADStudio/XE4/en/Using_the_XML_Data_Binding_Wizard

For other ways to work with xml you can look at the main index of the doc's here http://docwiki.embarcadero.com/RADStudio/XE4/en/Working_with_XML_documents_Index

Diego Garcia
  • 1,134
  • 1
  • 12
  • 25