Question

I have an XML file which I would like to parse and use to create an arguments set for ffmpeg encoding.

This is what a dump of the xml looks like:

$VAR1 = {
          'profile' => [
                       {
                         'enodingParam' => {
                                           'videoFrameRate' => {
                                                               'arg' => '-r',
                                                               'content' => '25'
                                                             },

                                           'audioCodec' => {
                                                           'arg' => '-acodec',
                                                           'content' => 'libfaac'
                                                         },
                                           'videoCodec' => {
                                                           'arg' => '-vcodec',
                                                           'content' => 'libx264'
                                                         },
                                           'videoSize' => {
                                                          'arg' => '-s',
                                                          'content' => '640x360'
                                                        },
                                           'audioBitrate' => {
                                                             'arg' => '-ab',
                                                             'content' => '96k'
                                                           },

                                           'videoGOP' => {
                                                         'arg' => '-g',
                                                         'content' => '90'
                                                       },
                                           'audioRate' => {
                                                          'arg' => '-ar',
                                                          'content' => '22050'
                                                        },
                                           'audioChannels' => {
                                                              'arg' => '-ac',
                                                              'content' => '2'
                                                            },
                                           'videoPreset' => {
                                                            'arg' => '-vpre',
                                                            'content' => 'slow'
                                                          },
                                           'videoBitrate' => {
                                                             'arg' => '-b',
                                                             'content' => '1200k'
                                                           }
                                         },
                         'metadat' => {
                                     'fileContainer' => '.mp4',
                                     'profileName' => 'testpfrof1'
                                   }
                       },
                       {
                         'enodingParam' => {
                                           'videoFrameRate' => {
                                                               'arg' => '-r',
                                                               'content' => '25'
                                                             },

                                           'audioCodec' => {
                                                           'arg' => '-acodec',
                                                           'content' => 'libfaac'
                                                         },
                                           'videoCodec' => {
                                                           'arg' => '-vcodec',
                                                           'content' => 'libx264'
                                                         },
                                           'videoSize' => {
                                                          'arg' => '-s',
                                                          'content' => '320x180'
                                                        },
                                           'audioBitrate' => {
                                                             'arg' => '-ab',
                                                             'content' => '96k'
                                                           },

                                                          },
                                           'videoGOP' => {
                                                         'arg' => '-g',
                                                         'content' => '90'
                                                       },
                                           'audioRate' => {
                                                          'arg' => '-ar',
                                                          'content' => '22050'
                                                        },
                                           'audioChannels' => {
                                                              'arg' => '-ac',
                                                              'content' => '2'
                                                            },
                                           'videoPreset' => {
                                                            'arg' => '-vpre',
                                                            'content' => 'slow'
                                                          },
                                           'videoBitrate' => {
                                                             'arg' => '-b',
                                                             'content' => '400k'
                                                           }
                                         },
                         'metadat' => {
                                     'fileContainer' => '.mp4',
                                     'profileName' => 'testProfile2'
                                   }
                       }
                     ]
        };

I would like to use a foreach loop for the encodingparam node/tagname and end up with a string which looks something like this:

-acodec libfaac -vcodec libx264 -s 640x360 -ab 96k 

I am kind of stuck . This is what I have put together so far:

#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;
use XML::LibXML;
my $filename = "xml/profile.xml";
my $parser = XML::LibXML->new;
my $doc    = $parser->parse_file($filename)
                or die "can't parse profile file: $@";
my $root = $doc->documentElement();
my @nodeList = $doc->getElementsByTagName('enodingParam');

here is the xml file

<?xml version="1.0"?>
<profiles>
        <profile>
                        <metadt>
                                <profileName>testp1</profileName>
                                <fileContainer>.mp4</fileContainer>
                        </metadt>
                        <enodingParam>
                                <videoCodec arg="-vcodec">libx264</videoCodec>
                                <videoPreset arg="-vpre">slow</videoPreset>
                                <videoBitrate arg="-b">1200k</videoBitrate>
                                <videoWidth arg="-w">640</videoWidth>
                                <videoHeight arg="-h">360</videoHeight>
                                <videoSize arg="-s">640x360</videoSize>
                                <videoFrameRate arg="-r">25</videoFrameRate>
                                <videoGOP arg ="-g">90</videoGOP>
                                <audioBitrate arg="-ab">ab 96k</audioBitrate>
                                <audioCodec arg="-acodec">-acodec libfaac</audioCodec>
                                <audioChannels arg="-ac">2</audioChannels>
                                <audioRate arg="-ar">"22050"</audioRate>
                        </enodingParam>
        </profile>
        <profile>
                        <metadt>
                                <profileName>testProfile22</profileName>
                                <fileContainer>.mp4</fileContainer>
                        </metadt>
                        <enodingParam>
                                <videoCodec arg="-vcodec">libx264</videoCodec>
                                <videoPreset arg="-vpre">slow</videoPreset>
                                <videoBitrate arg="-b">1200k</videoBitrate>
                                <videoWidth arg="-w">640</videoWidth>
                                <videoHeight arg="-h">360</videoHeight>
                                <videoSize arg="-s">640x360</videoSize>
                                <videoFrameRate arg="-r">25</videoFrameRate>
                                <videoGOP arg ="-g">90</videoGOP>
                                <audioBitrate arg="-ab">96k</audioBitrate>
                                <audioCodec arg="-acodec">libfaac</audioCodec>
                                <audioChannels arg="-ac">2</audioChannels>
                                <audioRate arg="-ar">22050</audioRate>
                        </enodingParam>
        </profile>

</profiles>

Modified the pl script to

use warnings;
use strict;
use Data::Dumper;
use XML::LibXML;
my $filename = "xml/book.xml";
my $parser = XML::LibXML->new;
my @ffmpegargs;
my $fileName="filename";
my $doc    = $parser->parse_file($filename)
                or die "can't parse profile file: $@";
my $root = $doc->documentElement();
my @paramList = $doc->getElementsByTagName('enodingParam');

for my $ele (@paramList)
{
    # You then need to iterate over all the children of that node...

    for my $param ($ele->nonBlankChildNodes())
    {

        my $inparams = " " . $param->getAttribute('arg') . " " . $param->textContent ;
        push ( @ffmpegargs, $inparams);

    }
    my $ffmpeg = join(" ", @ffmpegargs);
    print "ffmpeg" . $ffmpeg, "\n";
}

It is printing out correctly. Now how do i add the following to the string $filename , profileName, containerName (from the metadat node) to the same string so that my final output looks like:

ffmpeg -vcodec libx264  -vpre slow  -b 1200k  -w 640  -h 360  -s 640x360 filename_profileName_containerName 

ok tried zooming ue to profile. Not sure how to traverse the child nodes. Tried this. But its nor printing the right values

use warnings;
use strict;
use Data::Dumper;
use XML::LibXML;
my $filename = "xml/book.xml";
my $parser = XML::LibXML->new;
my @ffmpegargs;
my $fileName="filename";
my $doc    = $parser->parse_file($filename)
                or die "can't parse profile file: $@";
my $root = $doc->documentElement();
my @paramList = $doc->getElementsByTagName('profile');

for my $ele (@paramList)
{
    # You then need to iterate over all the children of that node...

    for my $param ($ele->findnodes('/encodingParam/*'))
    {

        my $inparams = " " . $param->getAttribute('arg') . " " . $param->textContent ;
        push ( @ffmpegargs, $inparams);

    }
    my $ffmpeg = join(" ", @ffmpegargs);
    print "ffmpeg" . $ffmpeg, "\n";
}
Was it helpful?

Solution

Ok, by the time you get to the end of your script, @nodeList is a list of XML::LibXML::Element objects.

So you start by iterating through each element of that list:

my @profiles = $doc->getElementsByTagName('profile');

for my $profile (@profiles)
{
    print $profile->getElementsByTagName('profileName')->get_node(1)->textContent;
    print $profile->getElementsByTagName('fileContainer')->get_node(1)->textContent;

    for my $param ($profile->getElementsByTagName('enodingParam')->get_node(1)->nonBlankChildNodes())
    {
        print " ";
        print $param->getAttribute('arg');
        print " ";
        print $param->textContent;
    }

    print "\n";
}

I'm using get_node(1) as a shortcut instead of calling getElementsByTagName, putting the result into an array and then working on the first element of the array.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top