tags:

views:

439

answers:

4

Hi I am a beginner programmer tyring to use TXMLparser with Delphi to just read a small xml file so I can understand how they work.

I have the following structure in xml file 'parser.xml' ;

<rule>
  <alert>priority 3</alert>
  <desc> </desc>
  <action>beep</action>
</rule>

And I have the following code in delphi

VAR
  Parser : TXmlParser;
  rule, alert: string;
  i:integer;

BEGIN
  Parser := TXmlParser.Create;
  Parser.Normalize := TRUE;
  Parser.LoadFromFile ('c:\parser.xml');
  Parser.StartScan;

  WHILE Parser.Scan DO
    CASE Parser.CurPartType OF
      ptStartTag,
      ptEmptyTag :            
        For i:=0 TO Parser.CurAttr.Count-1 Do
        Begin
          rule :=Parser.CurAttr.rule (i);
          alert :=Parser.CurAttr.alert (i);
      ptContent,
      ptCData    : // Process Parser.CurContent field here
      ptEndTag   : // Process End-Tag here (Parser.CurName)
      ptPI       : // Process PI here 
                   // (Parser.CurName is the target, Parser.CurContent)
    END;
  Parser.Free;
end.

I dont understand where, and with what syntax (e.g. or 'rule' or rule) I am to enter in the xml tags. I obtained the base of the code from the XML website, but the FOR loop is mine.. Seems to work ok but rule and alert come back as undeclared identifiers, even though they are set in VAR

Any help on where to enter and how to enter the tags and why identifiers arent recognised would be appreciated.

Thanks

+2  A: 

The for loop is your problem (or one of them):

  ptEmptyTag :            
        For i:=0 TO Parser.CurAttr.Count-1 Do
        Begin
          rule :=Parser.CurAttr.rule (i);
          alert :=Parser.CurAttr.alert (i);
        end; // <-- Insert end here
  ptContent,
  ptCData    : // Process Parser.CurContent field here
  ptEndTag   : // Process End-Tag here (Parser.CurName)
  ptPI       : // Process PI here 
               // (Parser.CurName is the target, Parser.CurContent)
end; // case
schnaader
The other end was for the case statement so it shouldn't be removed ;-)
Gamecat
Corrected, thanks.
schnaader
+3  A: 

Just a few remarks on the code:

  • please don't use uppercase for reserved words.
  • use try finally for created objects
  • use extra begin/end blocks for nested complex statements
  • you forgot an end ;-)
  • use functions
  • try to use an else clause in a case statement

/

procedure ProcessXML(const AFileName: string);
var
  Parser      : TXmlParser;
  rule, alert : string;
  i           : Integer; 

begin
  Parser := TXmlParser.Create;
  try
    Parser.Normalize := TRUE;
    Parser.LoadFromFile (AFileName);
    Parser.StartScan;

    while Parser.Scan do begin
      case Parser.CurPartType of
        ptStartTag,
        ptEmptyTag : begin            
          for i := 0 to Parser.CurAttr.Count-1 do begin
            rule :=Parser.CurAttr.rule (i);
            alert :=Parser.CurAttr.alert (i);
          end;
        end;
      ptContent,
      ptCData    : // Process Parser.CurContent field here
      ptEndTag   : // Process End-Tag here (Parser.CurName)
      ptPI       : // Process PI here 
                   // (Parser.CurName is the target, Parser.CurContent)
    else
      // Do something 
    end;

//

  finally
    Parser.Free;
  end;
end;

And call the function:

begin
  ProcessXML('c:\parser.xml');
end.

Look for information on TXMLParser on their site.

Gamecat
Good tips. +1 for that. I just don't like having 'begin' at the end of a line. In your example you see exactly why: you forgot a closing 'end;' to match 'while'. If begin was on a new line you'd see it in an eyeblink.
Wouter van Nifterick
+4  A: 

I'm not a user of TXMLParser, but a quick trip to the documentation section and FAQs page shows the problem.

The problem with the undeclared identifiers isn't because of the variables you've declared in the vars section; it's in the loop on the right side of the assignment (see lines ending in "// ****" comments:

VAR
  Parser : TXmlParser;
  rule, alert: string;
  i:integer;

BEGIN
  Parser := TXmlParser.Create;
  Parser.Normalize := TRUE;
  Parser.LoadFromFile ('c:\parser.xml');
  Parser.StartScan;

  WHILE Parser.Scan DO
    CASE Parser.CurPartType OF
      ptStartTag,
      ptEmptyTag :            
        For i:=0 TO Parser.CurAttr.Count-1 Do
        Begin
          rule := Parser.CurAttr.rule (i);   // **** problem here with .rule
          alert :=Parser.CurAttr.alert (i); // **** problem here with .alert
      ptContent,
      ptCData    : // Process Parser.CurContent field here
      ptEndTag   : // Process End-Tag here (Parser.CurName)
      ptPI       : // Process PI here 
                   // (Parser.CurName is the target, Parser.CurContent)
    END;
  Parser.Free;
end;

Nothing has established .rule() or .alert as methods of Parser.CurAttr, and you can't treat them as such. Try this instead:

rule := Parser.CurrAttr.Value('rule');
alert := Parser.CurrAttr.Value('alert');

Actually, now that I look more at the XML you posted, you're not dealing with attributes at all, but content instead. Attributes would be along the lines of:

<rule name="My rule" priority="3" alert="Very important">Other stuff</rule>

Still, I'll leave this post just because it explains the syntax error you were having regarding the undeclared identifiers.

Ken White
+1  A: 

Take a look at using Delphi's built in XML Databinding Wizard. It can create strongly typed class wrapper around the XML/schema so working with the XML is as easy as any other object.

ex. rule.Alert := 'Alert'; rule.Description := 'Hello'; rule.Action := 'beep';

KevinRF
While that might be a good suggestion, it's not an answer to the question asked. The XML Databinding Wizard isn't a solution to undeclared identifiers or using TXMLParser.
Ken White