2013-05-24 14 views
1

Я пытаюсь перенести некоторый код xml из стандартных подпрограмм delphi XML в NativeXML, надеюсь, чтобы улучшить скорость (много).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 не совсем то же самое, что и IXMLNodeChildNodes.

Как перечислить все дочерние узлы в родительском узле? Я не хочу давать каждому уникальное имя (<v1001>1234</v1001>, <v1002>4321</v1002>... и т. Д.), Так как мне только нужно получить к ним доступ последовательно и не нужно, чтобы ограничение скорости (или увеличенный размер файла) заключалось в том, чтобы сделать NodeByName для каждого значения (может быть много таких значений).

UPDATE **

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 требуется много десятков секунд.

+0

+1 Ну, с 'containers' простым и понятным. Ты прав. –

ответ

1

OP:

так что кажется, как будто свойство Nodes из TNativeXML не совсем же как собственность ChildNodes IXMLNode в.

Вы правы. Для достижения этого результата должно быть что-то еще.

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

+0

Спасибо за ваш вклад. Я понял это - на самом деле проще, чем это (я добавил обновленный код в качестве дополнения к вопросу) – rossmcm

+0

+1 для усилий! и для того, чтобы предупредить меня о «NextSibling». – rossmcm

Смежные вопросы