Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Use of uninitialized value in substitution (s///) error 1

Status
Not open for further replies.

simonchristieis

Programmer
Jan 10, 2002
1,144
GB
I'm new to Perl, just trying to create an xml file from a csv file:

Code:
{
my($fi) = $ARGV[0];
my($fo) = $ARGV[1];
my(@fields);
my(@fieldHeaders);
my($row);
my($i_count)=1;
my($ii_count)=0;
my($string);


sub trim($)
{
	$string = shift;
	$string =~ s/^\s+//;
	$string =~ s/\s+$//;
	$string =~ s/\s+//g;
	$string =~ s/\///g;
	return $string;
}

open(FI,$fi) || die("Cannot open $fi as input.\n");
open(FO,">$fo") || die("Cannot open $fo as output.\n");

print FO "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<RESULT>\n";

while ($row=<FI>)
	{
		chop($row);
		@fields = split(/,/,$row);

		if($i_count==1)
		{
		@fieldHeaders = split(/,/,$row);
		}


		if($i_count!=1)
		{
		print FO "<item>\n";
			foreach (@fieldHeaders)
			{
				print FO "<".trim($fieldHeaders[$ii_count]).">".trim($fields[$ii_count])."</".trim($fieldHeaders[$ii_count]).">\n";
				$ii_count=$ii_count+1;
			}

	        print FO "</item>\n";
		}
		$ii_count=0;
		$i_count=$i_count+1;
	}
print FO "</RESULT>\n";
close(FO);
close(FI);

}


The input file is of this format:

Code:
// field 1, field 2, field 3
value1, value2, value3

This is the error:
Code:
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 15, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 16, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 17, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 18, <FI> line 873.
Use of uninitialized value in concatenation (.) or string at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 43, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 15, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 16, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 17, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 18, <FI> line 873.
Use of uninitialized value in concatenation (.) or string at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 43, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 15, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 16, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 17, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 18, <FI> line 873.
Use of uninitialized value in concatenation (.) or string at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 43, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 15, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 16, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 17, <FI> line 873.
Use of uninitialized value in substitution (s///) at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 18, <FI> line 873.
Use of uninitialized value in concatenation (.) or string at D:\quic_shares_cr_prod\Releases\Library\v3.1.20\MeanReversionToXML.pl line 43, <FI> line 873.

Can anyone point me in the right direction to resolve the error ?

Thanks in advance

Simon
 
Hey,

Your code needs some critical adjustments.

The key issue you identified is caused by the fact that you are passing an undefined value to the trim() function. The codes current logic suggests that it would be impossible for a defined value ever to be passed to the trim() function.

While iterating the data, you assign @fieldHeaders only if $i_count is equal to "1". Beneath that, you execute the code that uses @fieldHeaders, if $i_count is not equal to "1", therefore @fieldHeaders will always be undefined when used.

Other issues:
- You don't make use of @fields (the actual data). I believe you meant to in places where @fieldHeaders is used. Due to this, its difficult to conceive what XML output you truly desire.
- Always use strict and warnings.
- The trim() function doesn't look right. You remove leading and trailing spaces, then lead onto remove all spaces anyway. Also, the removal of forward slashes doesn't suitably belong to a function named trim.
- My preference is to use the three way argument form of open with a lexical var filehandle.
- You probably meant to use chomp over chop. At the moment, if the last character of your input file isn't a new line, it will remove it anyway.
- You are combining the use of control loops and index counters unnecessarily / incorrectly. Specifically, there is no need for an index counter within the foreach loop. $_ already contains the current element, but its better to assign your own var.
- It looks as though your input data is in CSV format. It might be better to use a CSV module such as Text::CSV to handle.
- Its best to use one of the many modules available to write the XML for you, for many advantageous reasons. These include XML::Writer or even XML::Simple.

I would write an improved example, but as explained above, i'm uncertain of your desired output. I hope you are able to use the above to improve / fix your code.

Thanks,

Chris
 
I had nothing better to do therefore thought I would write an example :-D. Depending on the situation, my usual preference is to use Template Toolkit to generate XML / handle i.e. escaping myself, but XML Writer does the job here.

Code:
#! /usr/bin/perl
use strict;
use warnings;
use IO::File;
use Text::CSV;
use XML::Writer;

my ($csv_input_path, $xml_output_path) = @ARGV;

##########
# create objects.

my $xml_output_fh = IO::File->new( ">$xml_output_path" );
my $csv_input_fh = IO::File->new( "<$csv_input_path" );

my $xml_writer = new XML::Writer( OUTPUT => $xml_output_fh );

my $text_csv = Text::CSV->new ( { binary => 1 } ) or die Text::CSV->error_diag();
$text_csv->column_names( map { trim( $_ ) } @{$text_csv->getline( $csv_input_fh )} );

##########
# main.

$xml_writer->xmlDecl( 'UTF-8' );
$xml_writer->startTag( 'people' );
while ( my $row = $text_csv->getline_hr( $csv_input_fh ) )
{
	$xml_writer->startTag( 'person' );
	while ( my ($column, $value) = each ( %$row ) )
	{
		$xml_writer->startTag( $column );
		$xml_writer->characters( trim( $value ) );
		$xml_writer->endTag( $column );
	}
	$xml_writer->endTag( 'person' );
}
$xml_writer->endTag( 'people' );

##########
# kill objects.

$text_csv->eof or $text_csv->error_diag();

$xml_writer->end();

$csv_input_fh->close();
$xml_output_fh->close();

##########

sub trim
{
	my $v = shift;
	$v =~ s/^\s+//;
	$v =~ s/\s+$//;
	return $v;
}

Chris
 
Last thing,

I hadn't read your prints properly, and noticed you are indeed making use of @fields, therefore ignore my comments regarding. My example generates XML in the same format you desire (although no sorting).

Chris
 
Update to suit your requirements:

Code:
#! /usr/bin/perl
use strict;
use warnings;
use IO::File;
use Text::CSV;
use XML::Writer;

my $groups_node = 'RESULT';
my $group_node  = 'item';

my ($csv_input_path, $xml_output_path) = @ARGV;

##########
# create objects.

my $xml_output_fh = IO::File->new( ">$xml_output_path" );
my $csv_input_fh = IO::File->new( "<$csv_input_path" );

my $xml_writer = new XML::Writer( OUTPUT => $xml_output_fh );

my $text_csv = Text::CSV->new ( { binary => 1 } ) or die Text::CSV->error_diag();
$text_csv->column_names( $text_csv->getline( $csv_input_fh ) );

##########
# main.

$xml_writer->xmlDecl( 'UTF-8' );
$xml_writer->startTag( $groups_node );
while ( my $row = $text_csv->getline_hr( $csv_input_fh ) )
{
	$xml_writer->startTag( $group_node );
	while ( my ( $column, $value ) = each ( %$row ) )
	{
		$xml_writer->startTag( clean_column( $column ) );
		$xml_writer->characters( clean_value( $value ) );
		$xml_writer->endTag( clean_column( $column ) );
	}
	$xml_writer->endTag( $group_node );
}
$xml_writer->endTag( $groups_node );

##########
# kill objects.

$text_csv->eof or $text_csv->error_diag();

$xml_writer->end();

$csv_input_fh->close();
$xml_output_fh->close();

##########

sub clean_column
{
	my $c = shift;
	$c =~ s/\s+//g;
	$c = lc $c;
	return $c;
}

sub clean_value
{
	my $v = shift;
	$v =~ s/^\s+//;
	$v =~ s/\s+$//;
	return $v;
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top