1

I don't seem to be able to iterate through the following XML file.

<?xml version="1.0" encoding="utf-8"?>
    <Screen>
      <Title>MainMenuScrn</Title>
      <Start>True</Start>
      <BackColor>clBlue</BackColor>
      <Orientation>orLandscape</Orientation>
      <Image>&lt;none&gt;</Image>
      <tTFTImage>
        <Enabled>True</Enabled>
        <Fixed>False</Fixed>
        <Height>57</Height>
        <Image>HeatIcon</Image>
        <Left>40</Left>
        <Name>Image1</Name>
        <Parent>pnlScreenArea</Parent>
        <Top>49</Top>
        <Visible>True</Visible>
        <Width>57</Width>
      </tTFTImage>
      <tTFTStaticLabel>
        <Caption>Settings</Caption>
        <Enabled>True</Enabled>
        <Fixed>False</Fixed>
        <FontColor>clWhite</FontColor>
        <FontRef>BigBold</FontRef>
        <Height>16</Height>
        <Left>237</Left>
        <Name>StaticLabel3</Name>
        <Parent>pnlScreenArea</Parent>
        <Top>207</Top>
        <Visible>True</Visible>
        <Width>51</Width>
      </tTFTStaticLabel>
      <tTFTContainer>
        <BorderStyle>bsNone</BorderStyle>
        <Caption></Caption>
        <Color>clYellow</Color>
        <Enabled>True</Enabled>
        <Height>138</Height>
        <Left>59</Left>
        <Name>Container1</Name>
        <Parent>pnlScreenArea</Parent>
        <Top>58</Top>
        <Visible>True</Visible>
        <Width>202</Width>
        <tTFTButton>
          <Caption>Skip</Caption>
          <Color>clSilver</Color>
          <Enabled>True</Enabled>
          <Fixed>False</Fixed>
          <FontColor>clWindowText</FontColor>
          <FontRef>BigBold</FontRef>
          <Height>32</Height>
          <Left>20</Left>
          <Name>btnSkip</Name>
          <OnClick>btnSkip_OnClick</OnClick>
          <Parent>Container1</Parent>
          <Pen>78650656<Color>clBlack</Color><Width>1</Width></Pen>
          <PressColor>clBlack</PressColor>
          <Rounded>False</Rounded>
          <Top>97</Top>
          <Transparent>False</Transparent>
          <Visible>True</Visible>
          <Width>64</Width>
        </tTFTButton>
        <tTFTStaticLabel>
          <Caption>to set up or Skip to continue</Caption>
          <Enabled>True</Enabled>
          <Fixed>False</Fixed>
          <FontColor>clWindowText</FontColor>
          <FontRef>Default</FontRef>
          <Height>16</Height>
          <Left>18</Left>
          <Name>StaticLabel6</Name>
          <Parent>Container1</Parent>
          <Top>52</Top>
          <Visible>True</Visible>
          <Width>164</Width>
        </tTFTStaticLabel>
        <tTFTButton>
          <Caption>OK</Caption>
          <Color>clSilver</Color>
          <Enabled>True</Enabled>
          <Fixed>False</Fixed>
          <FontColor>clWindowText</FontColor>
          <FontRef>BigBold</FontRef>
          <Height>32</Height>
          <Left>124</Left>
          <Name>btnOK</Name>
          <OnClick>btnSkip_OnPress</OnClick>
          <Parent>Container1</Parent>
          <Pen>78650432<Color>clBlack</Color><Width>1</Width></Pen>
          <PressColor>clBlack</PressColor>
          <Rounded>True</Rounded>
          <Top>95</Top>
          <Transparent>False</Transparent>
          <Visible>True</Visible>
          <Width>64</Width>
        </tTFTButton>
        <tTFTStaticLabel>
          <Caption>since installation. Choose OK</Caption>
          <Enabled>True</Enabled>
          <Fixed>False</Fixed>
          <FontColor>clWindowText</FontColor>
          <FontRef>Default</FontRef>
          <Height>16</Height>
          <Left>18</Left>
          <Name>StaticLabel5</Name>
          <Parent>Container1</Parent>
          <Top>34</Top>
          <Visible>True</Visible>
          <Width>172</Width>
        </tTFTStaticLabel>
        <tTFTStaticLabel>
          <Caption>Controller has not been setup</Caption>
          <Enabled>True</Enabled>
          <Fixed>False</Fixed>
          <FontColor>clWindowText</FontColor>
          <FontRef>Default</FontRef>
          <Height>16</Height>
          <Left>18</Left>
          <Name>StaticLabel4</Name>
          <Parent>Container1</Parent>
          <Top>17</Top>
          <Visible>True</Visible>
          <Width>170</Width>
        </tTFTStaticLabel>
      </tTFTContainer>
    </Screen>

Using IXMLIntf and XMLDoc I have written a recursive routine which works down the XMLNodes. It all works fine until the first Object under tTFTContainer. I iterate through the nodes starting at FirstSibling and looping using NextSibling until the Node returned is nil. When I get to the tTFTButton, the node returned by NextSibling is actually the first child node of the tTFTButton (Caption). I can't pick up on the element tTFTButton.

I am using IsTextElement to determine if the Node is carrying a property. I had assumed that IsTextElement returning false would stop at tTFTButton so I could use this Node to pass back into my routine.

This is the routine....

function XMLToObject(ObjNode: IXMLNode;
                     Scrn: tfmWorkingScreen;
                     ParentCtrl: TWinControl): Boolean;
// Creates and Registers a TControl based on the XML definition of the object passed
// if object is a container all objects in that container will also be handled.
// Returns true if Object created and registered.

  function IsEvent(NodeName: String): Boolean;
  begin
    Result := (NodeName = 'OnClick')
           Or (NodeName = 'OnUp')
           Or (NodeName = 'OnPress')
           Or (NodeName = 'OnDown');
  end;

  Procedure SetPropVal(PropName: String; PropVal: String); //OleVariant);
  begin
    ObjProps.FindProperty(PropName).AsString := PropVal;
  end;

Var PropNode, SubNode: IXMLNode;
    ObjIdx: Integer;
    s: String;
begin
  Result := Assigned(ObjNode);
  if Assigned(ObjNode) then begin
    ObjIdx := IndexOfObject(ObjNode.NodeName);   // Index into Objects list
    if (ObjIdx > -1) and (ObjIdx < ObjCount) then begin
      PropNode := ObjNode.ChildNodes.FindNode('Name');
      ObjProps.Instance := CreateObj(PropNode.NodeValue,ObjIdx, Scrn, ParentCtrl);
      Scrn.RegisterAndAssign(TControl(ObjProps.Instance)); // register object to Screen
      Result := Assigned(ObjProps.Instance);   //
      if not result then begin
        PropNode := ObjNode.ChildNodes.First;
        while Assigned(PropNode) do begin
          if (PropNode.IsTextElement) then begin // if it is a property (Assumes Pen has propvalue)
          // This should also be done recursively
            if PropNode.ChildNodes.Count > 1 then begin // if it has child properties
              SubNode := PropNode.ChildNodes.First;
              while Assigned(SubNode) do begin
                s := PropNode.NodeName + '.' + SubNode.NodeName;
                ObjProps.FindProperty(s).AsString := subNode.NodeValue;
                SubNode := SubNode.NextSibling;
              end;
            end
          else 
            if IsEvent(PropNode.NodeName) then          // Set up the events
              Scrn.SetEventVal(ObjProps.Instance.Name, PropNode.NodeName, PropNode.Text);           
            ObjProps.FindProperty(PropNode.NodeName).AsString := PropNode.NodeValue; // Set property value
          end
          else
            begin
              SubNode := PropNode;
              while Assigned(SubNode) do begin
ShowMessage(SubNode.NodeName + '  ' + IntToStr(PropNode.ParentNode.ChildNodes.Count) + '  ' + PropNode.Text); // Debug
                Result := XMLToObject(SubNode, Scrn, TWinControl(ObjProps.Instance));   // recurse through container objects
                if Result then
                  SubNode := SubNode.NextSibling
                else
                  break;
              end;
            end;
          if Not Result then Break;                     // Get out if error
          PropNode := PropNode.NextSibling;             // move on to next item
        end;
      end;
    end;
  end;
end;

and this is how it is called. PropNode is the first XML node which carries object information....

    while Assigned(PropNode) do begin
      if XMLToObject(PropNode, WorkScrn, WorkScrn.pnlScreenArea) then
        PropNode := PropNode.NextSibling
      else
        begin
          MessageDlg('Unable to process ' + PropNode.NodeName + ' in ' + fFileName,
                     mtWarning, [mbOK], 0);
          break;
        end;
    end;

And here is the full XML file...

I hope that all makes sense. I am not sure if I am using XML correctly here, I was trying to make an XML version of a Text DMF file.

John Barrat
  • 810
  • 4
  • 15
  • 3
    We can't possibly tell you why your code isn't working if you don't include your code. – Ken White Jan 12 '15 at 20:19
  • 1
    Wouldn't it be easier if you used the DFM format and call the functions VCL uses to read it? – GabrielF Jan 13 '15 at 15:59
  • 1
    You might have a look at [this answer](http://stackoverflow.com/a/5089677/62576) to a somewhat similar question; it has some useful links to some existing libraries for serializing Delphi objects (including DFMs). – Ken White Feb 19 '15 at 21:22

0 Answers0