I'm trying to migrate some xml code from the default delphi XML routines to NativeXML, hopefully to improve the speed (a lot).
The XML files are of the form:
<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>
My problem is how to iterate through each of the sets of values. A more or less direct translation of the old code didn't work:
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 ;
The output I get is:
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
and I was expecting:
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
so it seems as if the Nodes
property of TNativeXML
is not exactly the same as IXMLNode
's ChildNodes
property.
How do I iterate all the child nodes within a parent node? I don't want to give each one a unique name (<v1001>1234</v1001>, <v1002>4321</v1002>...
etc), as I only ever need to access them sequentially, and don't want the speed penalty (or increased file size) of having to do a NodeByName
for every value (there can be many of these values).
UPDATE **
NativeXML does have an equivalent to ChildNodes
- it's called Containers
(not ChildContainers
as the online documentation would have you believe). The following worked:
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 ;
It's actually pretty slow - to read 32k float values takes many 10's of seconds.
OP :
You are right . There must be something more to be done to achieve this result.
Delphi 5 / Delphi XE2 NativeXml 4.07