nagesh has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have several VB files(.frm files). I want to convert this into XML files. These .frm files have the name value pairs. Note that there could be parent and child elements. The example of a VB .frm file is as below. Please let me know if there is a perl module or a program that I could use. If not please give me a suggestion as to how to go about. Thank you, Nagesh Yencharla
VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 6465 ClientLeft = 60 ClientTop = 345 ClientWidth = 11715 LinkTopic = "Form1" ScaleHeight = 6465 ScaleWidth = 11715 StartUpPosition = 3 'Windows Default Begin VB.Frame main_frame Caption = "Frame1" Height = 8775 Left = 0 TabIndex = 0 Top = 360 Width = 10695 Begin VB.TextBox sub_category_creator_text Height = 285 Left = 7320 TabIndex = 8 Top = 1680 Width = 1815 End Begin VB.TextBox category_creator_text Height = 285 Left = 2040 TabIndex = 6 Top = 1680 Width = 2295 End Begin VB.TextBox reference_number_text Height = 285 Left = 2040 TabIndex = 4 Top = 1200 Width = 2295 End Begin VB.TextBox title_text Height = 285 Left = 2040 TabIndex = 2 Top = 600 Width = 4695 End Begin VB.Image sub_category_picker_image Height = 375 Left = 9360 Top = 1680 Width = 375 End Begin VB.Label sub_category_creator Alignment = 1 'Right Justify Caption = "Sub Category (Creator)" Height = 375 Left = 5520 TabIndex = 7 Top = 1680 Width = 1695 End Begin VB.Image creator_picker_image Height = 375 Left = 4440 Top = 1680 Width = 375 End Begin VB.Label category_creator Alignment = 1 'Right Justify Caption = "Category (Creator)" Height = 375 Left = 360 TabIndex = 5 Top = 1680 Width = 1575 End Begin VB.Label reference_number Alignment = 1 'Right Justify Caption = "Reference Number" Height = 375 Left = 360 TabIndex = 3 Top = 1200 Width = 1575 End Begin VB.Label TitleLabel Alignment = 1 'Right Justify Caption = "Title*:" Height = 375 Left = 360 TabIndex = 1 Top = 600 Width = 1575 End End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Private Sub Label1_Click() End Sub Private Sub Title_Click() End Sub Private Sub Text2_Change() End Sub Private Sub question_text_Change() End Sub

Added ".frm" to title 2002-02-14 dvergin

Replies are listed 'Best First'.
Re: VB File to XML file
by steves (Curate) on Feb 15, 2002 at 05:28 UTC

    XML::Writer and recursion are your friends here. A lot depends on how you want the XML to look. Here's an example where everything is an element. You could also just make the settings per Begin/End block attributes of an element identified by Begin. That got pretty ugly with so many elements so I did it this way. It'll at least get you started. I set the XML::Writer UNSAFE attribute to get it forced through. You'll want to define your XML so it's real and you can get rid of that ...

    use strict; use XML::Writer; my $xml = XML::Writer->new(DATA_MODE => 1, DATA_INDENT => 4, UNSAFE => + 1); to_xml(); sub new_tag { my $tag = shift; $xml->startTag($tag); while (<DATA>) { chomp; if (/^\s*Begin\s+\S+\s+(\w+)\s*$/) { new_tag($1); } elsif (/^\s*End\s*$/) { $xml->endTag($tag); return; } elsif (/^\s*(\w+)\s*=\s*\"?(.+)\"?\s*$/) { $xml->startTag($1); $xml->characters($2); $xml->endTag($1); } } } sub to_xml { while (<DATA>) { chomp; new_tag($1) if (/^\s*Begin\s+\S+\s+(\w+)\s*$/); } } __DATA__ VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 6465 ClientLeft = 60 ClientTop = 345 ClientWidth = 11715 LinkTopic = "Form1" ScaleHeight = 6465 ScaleWidth = 11715 StartUpPosition = 3 'Windows Default Begin VB.Frame main_frame Caption = "Frame1" Height = 8775 Left = 0 TabIndex = 0 Top = 360 Width = 10695 Begin VB.TextBox sub_category_creator_text Height = 285 Left = 7320 TabIndex = 8 Top = 1680 Width = 1815 End Begin VB.TextBox category_creator_text Height = 285 Left = 2040 TabIndex = 6 Top = 1680 Width = 2295 End Begin VB.TextBox reference_number_text Height = 285 Left = 2040 TabIndex = 4 Top = 1200 Width = 2295 End Begin VB.TextBox title_text Height = 285 Left = 2040 TabIndex = 2 Top = 600 Width = 4695 End Begin VB.Image sub_category_picker_image Height = 375 Left = 9360 Top = 1680 Width = 375 End Begin VB.Label sub_category_creator Alignment = 1 'Right Justify Caption = "Sub Category (Creator)" Height = 375 Left = 5520 TabIndex = 7 Top = 1680 Width = 1695 End Begin VB.Image creator_picker_image Height = 375 Left = 4440 Top = 1680 Width = 375 End Begin VB.Label category_creator Alignment = 1 'Right Justify Caption = "Category (Creator)" Height = 375 Left = 360 TabIndex = 5 Top = 1680 Width = 1575 End Begin VB.Label reference_number Alignment = 1 'Right Justify Caption = "Reference Number" Height = 375 Left = 360 TabIndex = 3 Top = 1200 Width = 1575 End Begin VB.Label TitleLabel Alignment = 1 'Right Justify Caption = "Title*:" Height = 375 Left = 360 TabIndex = 1 Top = 600 Width = 1575 End End

    Output looks like this:

    <Form1> <Caption>Form1"</Caption> <ClientHeight>6465</ClientHeight> <ClientLeft>60</ClientLeft> <ClientTop>345</ClientTop> <ClientWidth>11715</ClientWidth> <LinkTopic>Form1"</LinkTopic> <ScaleHeight>6465</ScaleHeight> <ScaleWidth>11715</ScaleWidth> <StartUpPosition>3 'Windows Default</StartUpPosition> <main_frame> <Caption>Frame1"</Caption> <Height>8775</Height> <Left>0</Left> <TabIndex>0</TabIndex> <Top>360</Top> <Width>10695</Width> <sub_category_creator_text> <Height>285</Height> <Left>7320</Left> <TabIndex>8</TabIndex> <Top>1680</Top> <Width>1815</Width> </sub_category_creator_text> <category_creator_text> <Height>285</Height> <Left>2040</Left> <TabIndex>6</TabIndex> <Top>1680</Top> <Width>2295</Width> </category_creator_text> <reference_number_text> <Height>285</Height> <Left>2040</Left> <TabIndex>4</TabIndex> <Top>1200</Top> <Width>2295</Width> </reference_number_text> <title_text> <Height>285</Height> <Left>2040</Left> <TabIndex>2</TabIndex> <Top>600</Top> <Width>4695</Width> </title_text> <sub_category_picker_image> <Height>375</Height> <Left>9360</Left> <Top>1680</Top> <Width>375</Width> </sub_category_picker_image> <sub_category_creator> <Alignment>1 'Right Justify</Alignment> <Caption>Sub Category (Creator)"</Caption> <Height>375</Height> <Left>5520</Left> <TabIndex>7</TabIndex> <Top>1680</Top> <Width>1695</Width> </sub_category_creator> <creator_picker_image> <Height>375</Height> <Left>4440</Left> <Top>1680</Top> <Width>375</Width> </creator_picker_image> <category_creator> <Alignment>1 'Right Justify</Alignment> <Caption>Category (Creator)"</Caption> <Height>375</Height> <Left>360</Left> <TabIndex>5</TabIndex> <Top>1680</Top> <Width>1575</Width> </category_creator> <reference_number> <Alignment>1 'Right Justify</Alignment> <Caption>Reference Number"</Caption> <Height>375</Height> <Left>360</Left> <TabIndex>3</TabIndex> <Top>1200</Top> <Width>1575</Width> </reference_number> <TitleLabel> <Alignment>1 'Right Justify</Alignment> <Caption>Title*:"</Caption> <Height>375</Height> <Left>360</Left> <TabIndex>1</TabIndex> <Top>600</Top> <Width>1575</Width> </TitleLabel> </main_frame> </Form1>
    </code>
Re: VB .frm File to XML file
by mirod (Canon) on Feb 15, 2002 at 06:40 UTC

    You could use XML::Writer, but in this case it looks simple enough (famous last words!) so basic print statements probably work just fine. You could also generate SAX events from the file and then let a SAX writer take care of it of course.

    Anyway, my attempt is below, it stores everything in the form.

    Problems you might encounter:

    • potential tag names (VB.Form, VB.Frame...) might include characters that make them non valid XML element names, but this is easy to check,
    • you don't specify the character encoding of your file (UTF-8? pure-ASCII? ASCII extended?), if it is not UTF-8 (or pure ASCII, no accented character) then you will need to add an XML declaration
    #!/bin/perl -w use strict; my @context; my $FORM_TAG = "form"; my $SUB_TAG = "sub"; my $INDENT = " " x 2; while( <DATA>) { if( m{^\s*Begin\s+(\S+)\s+(\S+)\s*$}) { # Begin tag name my( $tag, $name)= ($1, escape_xml($2)); print $INDENT x @context; print qq{<$tag name="$name">\n}; push @context, $tag; } elsif( m{^\s*(\S+)\s*=\s*(.*)$}) { # key = value my( $tag, $value)= ($1, $2); print $INDENT x @context; $value= escape_xml( strip_quotes( $value)); print qq{<$tag>$value</$tag>\n}; } elsif( m{^\s*End\s*$}) { # End my $tag= pop @context; print $INDENT x @context; print qq{</$tag>\n}; } elsif( m{^Attribute\s*(\S*)\s*=\s*(.*)$}) { # Attribute att = val # Note: those could be stored as attribute to the main tag # but this would increase the code complexity as it # would need to buffer most of the data my( $attribute, $value)= ($1, $2); print $INDENT x @context; # may be unnecessary $value= escape_xml( strip_quotes( $value)); print qq{<$attribute>$value</$attribute>\n}; } elsif( m{^\s*Private Sub (\S*)\s*\(([^)]*)\)\s*$}) { # Private Sub sub(args) my( $sub, $args)= ( $1, escape_xml($2)); print $INDENT x @context; # may be unnecessary print qq{<$SUB_TAG name="$sub" args="$args">\n}; push @context, $SUB_TAG; } elsif( m{^\s*End Sub\s*$}) { # End Sub pop @context; print $INDENT x @context; # may be unnecessary print qq{</$SUB_TAG>\n}; } elsif( @context && ($context[-1] eq $SUB_TAG)) { # print everything within a sub # the 3 cases dealing with subs should probably be before # any other case, depending on the syntax of the subs # but it is easier to understand the code this way print $INDENT x @context; print escape_xml($_); } elsif( !@context && m{^\s*VERSION\s+(\S+)\s*$}) { # VERSION line my $version= escape_xml( $1); print qq{<$FORM_TAG version="$version">\n}; } } print qq{</$FORM_TAG>\n}; # strips quotes from a quoted string # could probably be made faster by working directly on $_[0] sub strip_quotes { my $string= shift; if( (substr( $string, 0, 1) eq '"') && (substr( $string, -1, 1) eq '"') ) { substr( $string, 0, 1)= ''; substr( $string, -1, 1) = ''; } return( $string); } # escape characters that would render the XML invalid sub escape_xml { my $string= shift; $string=~ s{&}{&amp;}g; $string=~ s{<}{&lt;}g; $string=~ s{"}{&quote;}g; # only needed for attributes return $string; } __DATA__ VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 6465 ScaleHeight = 6465 ScaleWidth = 11715 StartUpPosition = 3 'Windows Default Begin VB.Frame main_frame Caption = "Frame1" Height = 8775 Left = 0 TabIndex = 0 Top = 360 Width = 10695 Begin VB.TextBox sub_category_creator_text Height = 285 Left = 7320 TabIndex = 8 Top = 1680 Width = 1815 End Begin VB.TextBox category_creator_text Height = 285 Left = 2040 TabIndex = 6 Top = 1680 Width = 2295 End Begin VB.TextBox title_text Height = 285 Left = 2040 TabIndex = 2 Top = 600 Width = 4695 End Begin VB.Label reference_number Alignment = 1 'Right Justify Caption = "Reference Number" Height = 375 Left = 360 TabIndex = 3 Top = 1200 Width = 1575 End Begin VB.Label TitleLabel Alignment = 1 'Right Justify Caption = "Title*:" Height = 375 Left = 360 TabIndex = 1 Top = 600 Width = 1575 End End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Private Sub Label1_Click() End Sub Private Sub Title_Click() End Sub Private Sub Text2_Change() End Sub Private Sub question_text_Change() Haidee < Ho! End Sub
Re: VB .frm File to XML file
by dreadpiratepeter (Priest) on Feb 15, 2002 at 05:00 UTC
    You can keep a stack of contexts. Loop through line by line. Every time you find a begin line, push the name of the tag onto the stack and print the tag. (Keep an indent counter as well so that you can make pretty XML code).
    Every time you find an end line. print the close tag for the top of the stack then pop the stack.
    Any other line just prints itself as a tag:
    my @stack; my $ind=0; while (<LINES>) { if (/^\s*Begin\s+(\w+)\s+(\w+)$/) { print (' ' x $ind) . "<$1 name='$2'>\n"; push @stack,$1; $ind += 3; } elsif (/^\s*End\s*/) { $ind -= 3; print (' ' x $ind) . "<" . (pop @stack) . ">\n"; } else { print (' ' x $ind) . "<$_>\n"; # change to print tag however y +ou want } }


    My machine is going haywire and won't cut and paste, or print, or open any new windows, so I can't really test this, but the algorithm is sound. You'll probably want to add error checking and such.
    Good Luck,

    -pete
    Entropy is not what is used to be.

    Added ".frm" to title 2002-02-14 dvergin

Re: VB .frm File to XML file
by nagesh (Novice) on Feb 16, 2002 at 04:03 UTC
    Monks,

    Thanks a lot for all your help. Its amazing that I got so many replies in such a short time. You guys are really great.

    Thank you,

    Nagesh