Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 357
  • Last Modified:

parse a template file

Hi,

This is what I want to achieve:

I have a text file as following:
=====================================
<html>
<body>
  Name:<$MY_TAG FIELD=name>
  TEL :<$MY_TAG FIELD=tel>
</body>
</html>
=====================================
I want to write a c program that read in this template file and replace <$MY_TAG ??????> with the data I retrieved from a database. And then prints out this file.

Can someone please tell me what's the good algorithm to use? Should I read this file into memory first and processes it from there.
Or is there any third-party C library that can help me do this?

Thanks in advance.

0
samantha
Asked:
samantha
  • 3
  • 2
  • 2
  • +2
1 Solution
 
ufolk123Commented:
Hi samantha,

I do not feel this problem as that of a parsing problem .May be the reverse and correct logic of your problem is to read out an array of name and tel pairs and generate the an output in the form of template

<html>
<body>
  Name:<$MY_TAG FIELD=name>
  TEL :<$MY_TAG FIELD=tel>
</body>
</html>

So you do it this way,
Read each record from the database and
write a code genrerator(so called) which will take in ( name1,telno1) and print the result in the form of

<html>
<body>
  Name:<$MY_TAG FIELD=name1>
  TEL :<$MY_TAG FIELD=tel1>
</body>
</html>

This you acheive simple by a series of printfs.
printf("<html> \n <body> \n   Name:<$MY_TAG FIELD=");
printf("%s",name1);
printf(>TEL :<$MY_TAG FIELD=");
printf("%s",tel1);
printf("> \n </body> \n</html> ");

0
 
samanthaAuthor Commented:
Hi ufolk123,

Thanks for the answer. But that's not what I want. Maybe I didn't state the problem clearly. This is actually a CGI program.

Let's call this program test.c. And the template file template.txt:
=============================
<html>
<body>
  Name:<$MY_TAG FIELD=name>
  TEL :<$MY_TAG FIELD=phone>
</body>
</html>
=============================

And a database table like this:
==============================
ID       NAME        PHONE
01       Samantha    (111)111-1111
02       ufolk123    (222)222-2222
......
==============================

The program is invoked like this:

http://xx.com/test.exe?id=02&template= template.txt

This program then retrieves the Record 02 from the database and use the "template.txt" to generate the following result page:
=============================
<html>
<body>
  Name:ufolk123
  TEL :(222)222-2222
</body>
</html>
=============================

I don't want to hard code this file using printf() beacuse everytime you want to change the layout, you have to do it inside the code and recompile the program. With this template file, users of "test.exe" can always provide their own "template.txt".

Thanks,

0
 
DontPanicCommented:
Hmmm. Looks like a problem better suited to XML.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
arnondCommented:
I would use a kind of final state machine that will parse the input file.
I would read the input file char by char and look first, for a '<' then I 'd look of a '$', 'M', 'Y','_' etc....untill i get the string '<$MY_TAG FIELD=' now, I know that the following string (up to the next '>') is the requiered field. After knowing wat field it is, just use the database's interface as you normaly do.
BTW, while you look for the first '<' just read the char and output it if it's not '<'. Your code should look something like this:
----------------------------
char ch,needed_ch,temp_array[100];
int state=0; /* state will record the state of the FSM (i.e., how many chars we've read so far that match the string we're looking for.*/
FILE* in_file,out_file; /* assuming files are open...*/

while ((ch=getc(infile))!=EOF)
{
  switch (state)
  {
     case (0):
       needed_ch='<';
       break;
     case (1):
       needed_ch='$';
       break;
     case (2):
       needed_ch='M';
       break;
/* continue with cases */
  }
  if (ch==needed_ch) /* did we get what we wanted ? */
  {
     temp_array[state]=ch;
     temp_array[state+1]='\0'; /* terminating NULL*/
     if (state==MAX_NUM_OF_STATES) /* which is the length of '<$MY_TAG FIELD' */
     {
        /* do data base stuff here and output the correct field's value */
     }
  }  else /* didn't get what we wanted.*/
     {
       putc (ch,out_file); /* just output the given char*/
       state=0; /* start over*/
     }
}

----------------------------
Please note that this code wasn't tested and compiled so it may have some erros but it should give you a clear idea.

Arnon David.
0
 
alexoCommented:
Normally, this is a job for Lex/Yacc.
But since you want it in C, do something like the following:
(quick & dirty: no error checking performed, file names are constants...)

    #include <stdio.h>
    #include <string.h>

    #define IN "in.txt"
    #define OUT "out.txt"
    #define MAX_LEN 256
    #define TOKEN1 "<$MY_TAG FIELD="
    #define TOKEN2 '>'

    FILE* in = fopen(IN, "r");
    FILE* out = fopen(OUT, "w");
    char line[MAX_LEN];

    while (fgets(line, sizeof line, in))
    {
        char* p1 = strstr(line, TOKEN1);
        if (p1)
        {
            char value[MAX_LEN];
            char* field = strdup(p1 + sizeof TOKEN1);
            char* p2 = strchr(field, TOKEN2);
            *p1 = *p2 = 0;
    /*
            Now, 'field' contains the name of the desired
            field name.  You get it's value from the DB
            into the 'value' variable.
    */
            strcat(p1, value);
            strcat(p1, p2 + 1);
        }

        fputs(line, out);
    }

    fclose(in);
    fclose(out);
0
 
samanthaAuthor Commented:
Thanks a lot, guys.

arnond & alexo, both your answers are excellent.  I wish they had a way to let me split the points to both of you.

Since alexo has locked it, I am giving the points to him.  Sorry, arnond. But if you can tell me how I can give you the points, I will also give 100 points.

Thanks again.  

0
 
arnondCommented:
If you want to spend an extra 100 points, just post another (empty) question titled something like "points for arnond" and I'll "answer" it and you'll accept.
But, do that only if you want to.

Thanks,
Arnon David.
0
 
alexoCommented:
If you don't have enough points, I can give Arnon 100+A of my own (I got some spare since I rarely ask questions).  Post a comment here in case you like the idea.
0
 
arnondCommented:
it's ok, she already posted one.

thanks anyway,
Arnon David.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 3
  • 2
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now