3

I am trying to access some Nodes in my XML File, but I cant get it working because i probably don't understand XML-Namepsaces in Delphi.

<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time="2018-01-18">
            <Cube currency="USD" rate="1.2235"/>
            <Cube currency="JPY" rate="136.07"/>
            <Cube currency="BGN" rate="1.9558"/>
            <Cube currency="CZK" rate="25.365"/>
            <Cube currency="DKK" rate="7.4475"/>
            <Cube currency="GBP" rate="0.88208"/>
            <Cube currency="HUF" rate="308.51"/>
            <Cube currency="PLN" rate="4.1665"/>
            <Cube currency="RON" rate="4.6480"/>
            <Cube currency="SEK" rate="9.8305"/>
            <Cube currency="CHF" rate="1.1748"/>
            <Cube currency="NOK" rate="9.6013"/>
            <Cube currency="HRK" rate="7.4409"/>
            <Cube currency="RUB" rate="69.2126"/>
            <Cube currency="TRY" rate="4.6374"/>
            <Cube currency="AUD" rate="1.5311"/>
            <Cube currency="BRL" rate="3.9321"/>
            <Cube currency="CAD" rate="1.5229"/>
            <Cube currency="CNY" rate="7.8582"/>
            <Cube currency="HKD" rate="9.5648"/>
            <Cube currency="IDR" rate="16325.38"/>
            <Cube currency="ILS" rate="4.1950"/>
            <Cube currency="INR" rate="78.1210"/>
            <Cube currency="KRW" rate="1306.61"/>
            <Cube currency="MXN" rate="22.8174"/>
            <Cube currency="MYR" rate="4.8396"/>
            <Cube currency="NZD" rate="1.6759"/>
            <Cube currency="PHP" rate="62.068"/>
            <Cube currency="SGD" rate="1.6175"/>
            <Cube currency="THB" rate="39.054"/>
            <Cube currency="ZAR" rate="15.0035"/>
        </Cube>
    </Cube>
</gesmes:Envelope>

I tried to access the Cube Nodes like that:

procedure TForm2.Button1Click(Sender: TObject);
var
  Doc: IXMLDocument;
  Node: IXMLNode;
  sl: TStringList;
begin
  Doc := LoadXMLDocument('C:\Users\Kevin\Desktop\test.xml');
  node := Doc.DocumentElement;

  ShowMessage(Node.ChildNodes['Cube']);
end;

I realized that my output is: "gesmes:Cube". I don't think that is right... I excpected to get the the first "Cube" Node. I am not sure how namespaces in Delphi work so it would be great if i could get some help here.

Best Regards!

1 Answer 1

8

You are passing an IXMLNode interface pointer to ShowMessage(), which expects a string instead. So presumably, in your real code, you have actually done ShowMessage(Node.ChildNodes['Cube'].NodeName); instead.

Which indeed reports 'gesmes:Cube', which is not what you are expecting. The Cube you want is in the http://www.ecb.int/vocabulary/2002-08-01/eurofxref namespace, which is different than the namespace of its parent Envelope (http://www.gesmes.org/xml/2002-08-01). So what actually happens is that DocumentElement.ChildNodes['Cube'] tries to find a Cube in the Envelope's namespace, finds no such element, so TXMLDocument creates a new one because the doNodeAutoCreate flag is enabled by default in the Doc.Options property. That is the Cube that DocumentElement.ChildNodes['Cube'] returns, not the Cube you want.

Because the Envelope and its immediate Cube child are in different namespaces, you can't use ChildNodes['Cube'] on the DocumentElement, you have to use ChildNodes.FindNode() instead, specifying the Cube's actual namespace:

Node := Doc.DocumentElement;
Node := Node.ChildNodes.FindNode('Cube', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref');

The next Cube is in the same namespace as its parent Cube, so you can use ChildNodes['Cube'] to get it:

Node := Node.ChildNodes['Cube'];

Then you can access the time attribute, if needed:

Node.Attributes['time']

And loop through the remaining child Cubes:

Node := Node.ChildNodes.First;
while Node <> nil do
begin
  if Node.LocalName = 'Cube' then
  begin
    // use Node.Attributes['currency'] and Node.Attributes['rate'] as needed...
  end;
  Node := Node.NextSibling;
end;

Here is the complete code:

procedure TForm2.Button1Click(Sender: TObject);
var
  Doc: IXMLDocument;
  Node: IXMLNode;
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    Doc := LoadXMLDocument('C:\Users\Kevin\Desktop\test.xml');
    try
      Node := Doc.DocumentElement;
      if Node = nil then ... // handle the error as needed...

      Node := Node.ChildNodes.FindNode('Cube', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref');
      if Node = nil then ... // handle the error as needed...

      Node := Node.ChildNodes['Cube'];
      if Node = nil then ... // handle the error as needed...

      Node := Node.ChildNodes.First;
      while Node <> nil do
      begin
        if Node.LocalName = 'Cube' then
          sl.Add(Node.Attributes['currency'] + '=' + Node.Attributes['rate']);
        Node := Node.NextSibling;
      end;
    finally
      Node := nil;
      Doc := nil;
    end;

    // use sl as needed...

  finally
    sl.Free;
  end;
end;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much, that helped. Even if its a little late now. The Project was paused for some time

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.