0

I am trying to convert json file to xml. So JSON directory is scanned and if any file that arrives there will be converted to xml and moved to xml directory.

But I am getting this error

readline() on closed filehandle $fh at json.pl line 29.
Malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)") at json.pl line 34

json.pl

#!/usr/bin/perl

use strict;
use warnings;
use File::Copy;

binmode STDOUT, ":utf8";
use utf8;

use JSON;
use XML::Simple;

# Define input and output directories
my $indir = 'json';
my $outdir = 'xml';

# Read input directory
opendir DIR, $indir or die "Failed to open $indir";
my @files = readdir(DIR);
closedir DIR;

# Read input file in json format
for my $file (@files) 
{
my $json;
{
    local $/; #Enable 'slurp' mode
    open my $fh, "<", "$indir/$file";
    $json = <$fh>;
    close $fh;
}

# Convert JSON format to perl structures
my $data = decode_json($json);

# Output as XML
open OUTPUT, '>', "$outdir/$file" or die "Can't create filehandle: $!";
select OUTPUT; $| = 1;
print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
print XMLout($data);
print "\n" ;
close(OUTPUT);
unlink "$indir/$file";

}

example.json

{
"Manager":
    {
        "Name" : "Mike",
        "Age": 28,
        "Hobbies": ["Music"]
     },
"employees":
    [
        {
            "Name" : "Helen",
            "Age": 26,
            "Hobbies": ["Movies", "Tennis"]
           },
        {
            "Name" : "Rich",
            "Age": 31,
            "Hobbies": ["Football"]

        }
    ]
}

2 Answers 2

4

You aren't checking for errors during open, and you aren't skipping directory entries (readdir will return . and .. entries).

If you use

open my $fh, "<", "$indir/$file" or die "$file: $!";

you'll probably find the problem quickly.

"readline() on closed filehandle $fh" is saying "open $fh failed but you kept going anyway".

Sign up to request clarification or add additional context in comments.

Comments

0

As @cjm has pointed out, the problem is that you are trying to open and read directories as well as files from your source directory.

This is a fix for that, and it also uses autodie to avoid constantly checking the status of all the IO operations. I've also tidied things up a bit.

#!/usr/bin/perl

use utf8;
use strict;
use warnings;
use autodie;

use open qw/ :std :encoding(utf8) /;

use JSON qw/ decode_json /;
use XML::Simple qw/ XMLout /;

my ($indir, $outdir) = qw/ json xml /;

my @indir = do {
  opendir my $dh, $indir;
  readdir $dh;
};

for my $file (@indir) {

  my $infile = "$indir/$file";
  next unless -f $infile;

  my $json = do {
    open my $fh, '<', $infile;
    local $/;
    <$fh>;
  };

  my $data = decode_json($json);

  my $outfile = "$outdir/$file";
  open my $out_fh, '>', "$outdir/$file";
  print $out_fh '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>', "\n";
  print $out_fh XMLout($data), "\n";
  close $out_fh;

  unlink $infile;
}

1 Comment

Would it be good to put a eval around the decode_json in order to handle failures? decode_json croaks on errors.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.