Delphi - 使用NativeXML迭代XML数据集

时间:2013-05-24 09:19:47

标签: 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

因此Nodes TNativeXML属性似乎与IXMLNode的{​​{1}}属性不完全相同。

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

更新**

NativeXML确实等同于NodeByName - 它被称为ChildNodes(不是Containers,因为在线文档会让您相信)。以下工作:

ChildContainers

它实际上非常慢 - 读取32k浮点值需要10秒钟。

1 个答案:

答案 0 :(得分:2)

OP:

  

所以似乎TNativeXML的Nodes属性不完全是   与IXMLNode的ChildNodes属性相同。

你是对的。必须要做更多的事情来实现这一结果。

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