Delphi - 使用 NativeXML 迭代 XML 数据集

标签 delphi xml-parsing delphi-2006 nativexml

我正在尝试将一些 xml 代码从默认的 delphi XML 例程迁移到 NativeXML,希望能够提高速度(很多)。

XML 文件的格式为:

<Datafile>
  <Header>
    <Name>'My Name'</Name>
    <Address>'My Address'</Address>
  </Header>
  <Body>
    <ValuesSets>
      <ValuesSet>
        <v>1</v>
        <v>2</v>
        <v>3</v>
        <v>4</v>
      </ValuesSet>
      <ValuesSet>
        <v>5</v>
        <v>6</v>
        <v>7</v>
        <v>8</v>
      </ValuesSet>
    </ValuesSets>
  </Body>
</Datafile>

我的问题是如何迭代每组值。旧代码或多或少的直接翻译不起作用:

procedure TForm1.Button1Click(Sender: TObject);

var
    AXMLDoc       : TNativeXML ;
    FileID        : TFilename ;
    I             : Integer ;
    J             : Integer ;
    HeaderNode    : TXMLNode ;
    BodyNode      : TXMLNode ;
    ValuesSetsNode : TXMLNode ;
    ValuesSetNode  : TXMLNode ;

    Values         : array of array of integer ;

begin
try
    Memo1.Lines.Clear ;
    FileID := 'Sample.XML' ;
    Memo1.Lines.LoadFromFile (FileID) ;
    AXMLDoc := TNativeXml.Create (nil) ;
    AXMLDoc.LoadFromFile (FileID) ;

    if Assigned(AXMLDoc.Root) then
        begin
        HeaderNode := AXMLDoc.Root.NodeByName ('Header') ;
        if Assigned (HeaderNode) then
            begin
            //  < process header items >
            BodyNode := AXMLDoc .Root.NodeByName ('Body') ;
            if Assigned (BodyNode) then
                begin
                ValuesSetsNode := BodyNode.NodeByName ('ValuesSets') ;
                if Assigned (ValuesSetsNode) then
                    begin
                    SetLength (Values, ValuesSetsNode.NodeCount) ;
                    for i := 0 to ValuesSetsNode.NodeCount - 1 do
                        begin
                        ValuesSetNode := ValuesSetsNode [i] ;
                        if Assigned (ValuesSetNode) then
                            begin
                            SetLength (Values [i], ValuesSetNode.NodeCount) ;
                            for j := 0 to ValuesSetNode.NodeCount - 1 do
                                begin
                                Values [i, j] := StrToIntDef (ValuesSetNode [j].Value, 0) ;
                                end ;
                            end ;
                       end ;
                    end ;
                end ;
            end ;
        end ;

    for i := 0 to Length (Values) - 1 do
        begin
        for j := 0 to Length (Values [i]) - 1 do
            begin
            Memo1.Lines.Add (Format ('Values [%d, %d] = %d', [i, j, Values [i, j]])) ;
            end ;
       end ;

finally
    FreeAndNil (AXMLDoc) ;
    end ;
end ;

我得到的输出是:

Values [1, 0] = 0
Values [1, 1] = 1
Values [1, 2] = 0
Values [1, 3] = 2
Values [1, 4] = 0
Values [1, 5] = 3
Values [1, 6] = 0
Values [1, 7] = 4
Values [1, 8] = 0
Values [3, 0] = 0
Values [3, 1] = 5
Values [3, 2] = 0
Values [3, 3] = 6
Values [3, 4] = 0
Values [3, 5] = 7
Values [3, 6] = 0
Values [3, 7] = 8
Values [3, 8] = 0

我期待的是:

Values [0, 0] = 1
Values [0, 1] = 2
Values [0, 2] = 3
Values [0, 3] = 4
Values [1, 0] = 5
Values [1, 1] = 6
Values [1, 2] = 7
Values [1, 3] = 8

所以看起来 NodesTNativeXML 属性与 IXMLNodeChildNodes 属性并不完全相同。

如何迭代父节点中的所有子节点?我不想给每个值一个唯一的名称( <v1001>1234</v1001>, <v1002>4321</v1002>... 等),因为我只需要按顺序访问它们,并且不希望因必须为每个值执行 NodeByName 而造成速度损失(或增加文件大小) (这些值可以有很多)。

更新**

NativeXML 确实有一个与 ChildNodes 等效的值 - 它被称为 Containers(不是在线文档让您相信的 ChildContainers)。以下工作有效:

var
    AXMLDoc       : TNativeXML ;
    FileID        : TFilename ;
    I             : Integer ;
    J             : Integer ;
    HeaderNode    : TXMLNode ;
    BodyNode      : TXMLNode ;
    ValuesSetsNode : TXMLNode ;
    ValuesSetNode  : TXMLNode ;

    Values         : array of array of integer ;

begin
try
    Memo1.Lines.Clear ;
    FileID := 'Sample.XML' ;
    Memo1.Lines.LoadFromFile (FileID) ;
    AXMLDoc := TNativeXml.Create (nil) ;
    AXMLDoc.LoadFromFile (FileID) ;

    if Assigned(AXMLDoc.Root) then
        begin
        HeaderNode := AXMLDoc.Root.NodeByName ('Header') ;
        if Assigned (HeaderNode) then
            begin
            //  < process header items >
            BodyNode := AXMLDoc .Root.NodeByName ('Body') ;
            if Assigned (BodyNode) then
                begin
                ValuesSetsNode := BodyNode.NodeByName ('ValuesSets') ;
                if Assigned (ValuesSetsNode) then
                    begin
                    SetLength (Values, ValuesSetsNode.ContainerCount) ;
                    for i := 0 to ValuesSetsNode.ContainerCount - 1 do
                        begin
                        ValuesSetNode := ValuesSetsNode.Containers [i] ;
                        if Assigned (ValuesSetNode) then
                            begin
                            SetLength (Values [i], ValuesSetNode.ContainerCount) ;
                            for j := 0 to ValuesSetNode.ContainerCount - 1 do
                                begin
                                Values [i, j] := StrToIntDef (ValuesSetNode.Containers [j].Value, 0) ;
                                end ;
                            end ;
                       end ;
                    end ;
                end ;
            end ;
        end ;

    for i := 0 to Length (Values) - 1 do
        begin
        for j := 0 to Length (Values [i]) - 1 do
            begin
            Memo1.Lines.Add (Format ('Values [%d, %d] = %d', [i, j, Values [i, j]])) ;
            end ;
       end ;

finally
    FreeAndNil (AXMLDoc) ;
    end ;
end ;

实际上相当慢 - 读取 32k 浮点值需要数十秒的时间。

最佳答案

操作:

so it seems as if the Nodes property of TNativeXML is not exactly the same as IXMLNode's ChildNodes property.

你说得对。为了实现这一结果,必须采取更多措施。

enter image description here

procedure TForm1.Button1Click(Sender: TObject);
var
[...]
    i , i2        : Integer ;
    j , j2        : Integer ;
[...]
begin
try
    Memo1.Lines.Clear ;
    [...]
            BodyNode := AXMLDoc .Root.NodeByName ('Body') ;
             if Assigned (BodyNode) then
             begin
                 ValuesSetsNode := BodyNode.NodeByName ('ValuesSets') ;
                 if Assigned (ValuesSetsNode) then
                 begin
                     SetLength (Values, ValuesSetsNode.NodeCount) ;
                     ValuesSetNode := ValuesSetsNode.NodeByName('ValuesSet') ;
                     if Assigned (ValuesSetNode) then
                     begin
                       i2:=0;
                        for i := 0 to ValuesSetSNode.NodeCount - 1 do begin
                         if i > 0 then ValuesSetNode := ValuesSetsNode.NextSibling(ValuesSetNode) ;
                         if ValuesSetNode=nil then break;
                         if ValuesSetNode.NodeCount > 0 then begin
                            SetLength(Values[i2], ValuesSetNode.NodeCount) ;
                            j2:=0;
                               for j := 0 to ValuesSetNode.NodeCount - 1 do begin
                                if pos(#13,ValuesSetNode[j].Value) > 0 then continue;
                                Values [i2, j2] := StrToIntDef (ValuesSetNode[j].Value, 0) ;
                                inc(j2);
                               end ; // for j
                           SetLength(Values[i2],j2);
                           inc(i2);
                         end;
                        end ; // for i
                     end;     // ValuesSetNode
                 end;         // ValuesSetsNode
             end;             // BodyNode
        end;                  // HeaderNode
    end;                      // AXMLDoc.Root

[...] 

finally
    FreeAndNil (AXMLDoc) ;
    end ;
end ;

Delphi 5/Delphi XE2 NativeXml 4.07

关于Delphi - 使用 NativeXML 迭代 XML 数据集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16731527/

相关文章:

javascript - 获取子节点时 XML Null

Delphi 2006 - 分配动态数组函数结果

德尔福西雅图 : I get an Invalid Pointer operation when freeing an object I created

delphi - 为什么 TEdit 中的文本剪辑在第一次创建时没有改变

android - 格式错误的 url 异常 :protocol not found while adding or deleting data from xml in android?

php - PHP 中简单干净的 xml 操作

delphi - Delphi 中的单元测试 - 你做得怎么样?

delphi - 如何制作一个透明背景的TScrollBox?

delphi - 如何创建彩虹渐变的一部分

delphi - 在某些CPU上的紧密循环中ADC/SBB和INC/DEC的问题