Delphi中的XML命名空间

3

我正在尝试访问XML文件中的一些节点,但由于我可能不理解Delphi中的XML命名空间,无法使其工作。

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

我尝试通过以下方式访问Cube节点:

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;

我发现我的输出是:"gesmes:Cube"。我认为这不是正确的... 我期望得到第一个 "Cube" 节点。我不确定 Delphi 中的命名空间是如何工作的,如果能在这里得到一些帮助就太好了。
最好的问候!
1个回答

8
你正在将一个IXMLNode接口指针传递给期望一个stringShowMessage()函数。因此,假设在你的实际代码中,你实际上已经执行了ShowMessage(Node.ChildNodes['Cube'].NodeName);
这确实报告了'gesmes:Cube',这不是你所期望的。你想要的Cube位于http://www.ecb.int/vocabulary/2002-08-01/eurofxref命名空间中,而不是其父级Envelopehttp://www.gesmes.org/xml/2002-08-01)的命名空间。因此,实际发生的是DocumentElement.ChildNodes['Cube']尝试在Envelope的命名空间中查找Cube,未找到这样的元素,因此TXMLDocument创建一个新的,因为Doc.Options属性中默认启用了doNodeAutoCreate标志。那就是DocumentElement.ChildNodes['Cube']返回的Cube,而不是你想要的Cube
由于Envelope及其直接子级Cube位于不同的命名空间中,因此无法在DocumentElement上使用ChildNodes['Cube'],而必须使用ChildNodes.FindNode(),同时指定Cube的实际命名空间。
Node := Doc.DocumentElement;
Node := Node.ChildNodes.FindNode('Cube', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref');

下一个 Cube 与其父级 Cube 在同一命名空间中,因此您可以使用 ChildNodes ['Cube'] 来获取它。
Node := Node.ChildNodes['Cube'];

如果需要,您可以访问time属性:

Node.Attributes['time']

循环遍历其余的子Cube

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;

以下是完整代码:

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;

非常感谢,那很有帮助。即使现在有点晚了。该项目已经暂停了一段时间。 - Kevin Böhmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接