Hi all,

I am in fruit industry and dealing with stock inventory of fruits.
I got 2 files, one file got fruit names (fruit.txt) and other file got the inventory status (status.txt).

Task for me was to check the fruit list and update the inventory status:

Contents of the files:

1st file (fruit.txt):
=====================

rambutan
guava
apple
lychee
durian

2nd File (status.txt):
======================
<data>
<apple>
<In_Stock>true</In_Stock>
</apple>
<orange>
<In_Stock>true</In_Stock>
</orange>
<banana>
<In_Stock>false</In_Stock>
</banana>
<coconut>
<In_Stock>true</In_Stock>
</coconut>
<rambutan>
<In_Stock>false</In_Stock>
</ramputan>
<melon>
<In_Stock>true</In_Stock>
</melon>
<palm>
<In_Stock>true</In_Stock>
</palm>
<guava>
<In_Stock>false</In_Stock>
</guava>
<grapes>
<In_Stock>true</In_Stock>
</grapes>
<jackfruit>
<In_Stock>false</In_Stock>
</jackfruit>

</data>

When comparing the files, need to take one fruit at a time and see if it exists in the status file. If exists then need to check whether <In_Stock> flag is set to true or false. If true then need not do nothing. If false then need to change it to true. If the file does not exist in the status file then append the status file with the fruit info in format:

<fruit>
<In_Stock>true</In_Stock>
</fruit>


I am a novice in PERL with great enthusiasm. I solved the problem but it took nearly 100 lines of code for that. Someone commented that the code is not elegant although it does what it is supposed to do.

#!/usr/bin/perl
use strict;
use warnings;

use XML::Simple;

my $fr = 'fruit.txt';
open (my $fh, '<', $fr) or die "Unable to open $fr: $!";
my @fruits = <$fh>;
chomp @fruits;

my $status = 'status.txt';

my $hashref = XMLin($status);

foreach(@fruits){
    $hashref->{$_}->{'In_Stock'} = 'true';
}

print "<data>\n";
foreach (keys %{$hashref}){
    print "\t<$_>\n\t\t<In_Stock>\n\t\t\t$hashref->{$_}->{'In_Stock'}\n\t\t</In_Stock>\n\t</$_>\n";
}
print "</data>\n";

This gives the following output:

<data>
	<grapes>
		<In_Stock>
			true
		</In_Stock>
	</grapes>
	<guava>
		<In_Stock>
			true
		</In_Stock>
	</guava>
	<rambutan>
		<In_Stock>
			true
		</In_Stock>
	</rambutan>
	<apple>
		<In_Stock>
			true
		</In_Stock>
	</apple>
	<orange>
		<In_Stock>
			true
		</In_Stock>
	</orange>
	<durian>
		<In_Stock>
			true
		</In_Stock>
	</durian>
	<banana>
		<In_Stock>
			false
		</In_Stock>
	</banana>
	<coconut>
		<In_Stock>
			true
		</In_Stock>
	</coconut>
	<palm>
		<In_Stock>
			true
		</In_Stock>
	</palm>
	<jackfruit>
		<In_Stock>
			false
		</In_Stock>
	</jackfruit>
	<lychee>
		<In_Stock>
			true
		</In_Stock>
	</lychee>
	<melon>
		<In_Stock>
			true
		</In_Stock>
	</melon>
</data>

Looks good and elegant!

I could not however test the code yet. When I ran the script I got the following error, which I believe have something to do with PERL module? I am not sure how to get around with it but perhaps Gooling will help (unless you advise ...)

C:\fruit>fruit.pl

mismatched tag at line 16, column 2, byte 228 at C:/APPS/actperl/site/lib/XML/Pa
rser.pm line 168

C:\fruit>

One additional question:
Here your solution is printing data on screen. Would it be possible to redirect it to the status.txt file so it gets updated during runtime. That is the origianl goal ...

Most appreciated is your knowledge sharing.
Cheers
Boshu

mismatched tag at line 16, column 2, byte 228 at :/APPS/actperl/site/lib/XML/Parser.pm line 168

That is not valid xml format what you post. Goto 16 th line for and change 'ramputan' to 'rambutan'.

Here I add the code, that affect the changes in the xml file. ( Thanks d5e5 )

#!/usr/bin/perl
use strict;
use warnings;

use XML::Simple;

my $fr = 'fruit.txt';
open (my $fh, '<', $fr) or die "Unable to open $fr: $!";
my @fruits = <$fh>;
close ($fh);
chomp(@fruits);

my $status = 'status.txt';

my $hashref = XMLin($status);

### Status update in hash
foreach(@fruits){
	    $hashref->{$_}->{'In_Stock'} = 'true';
}

### print the update value $status
print XMLout(
       $hashref,
	        rootname => 'data',
		NoAttr => 1,
		OutputFile => $status,
       );

Edited 5 Years Ago by k_manimuthu: n/a

Many Thanks!

I got an error on when running the code:

H:\>perl fruits.pl
Unrecognised option: NoAttr at fruits.pl line 26

Perl version in use: 5.6.1

Regards,
Boshu

Hi.

I have now updated the XML::Simple module to (1.06 => 2.18) and the problem no longer persists.

XML::Simple is a new module for me (like pretty much anything in PERL). I have browsed the docs and tried to understand the syntax's used in yours and David's script.

The original file I have been talking about looks like below:

<configuration name="variant" version="2.91.0" xmlns="http://www.fruits.com/xml/confml/2" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <data>
  <apple>
      <In_Stock>true</In_Stock>
    </apple>
  <guava>
      <In_Stock>false</In_Stock>
    </guava>
  <lychee>
    <In_Stock>true</In_Stock>
  	</lychee>
  <jackfruit>
    <In_Stock>false</In_Stock>
  	</jackfruit>
  <banana>
    <In_Stock>true</In_Stock>
  	</banana>
  <melon>
    <In_Stock>true</In_Stock>
  	</melon>
  <grapes>
    <In_Stock>false</In_Stock>
  	</grapes>
  <pineapple>
  	<In_Stock>true</In_Stock>
  	</pineapple>
  </data>
</configuration>

Please note the beginning and ending line with tag <Configuration....>. Can those be left untouched when appending the file contents? Those must remain as is in the updated file.

I had my own experiment in in this but could not succeed.

Regards
Boshu

I modified Mani's solution a little, mostly changing optional parameters for the XMLin and XMLout methods.

#!/usr/bin/perl
use strict;
use warnings;

use XML::Simple;

my $fr = 'fruit.txt';
open (my $fh, '<', $fr) or die "Unable to open $fr: $!";
my @fruits = <$fh>;
close ($fh);
chomp(@fruits);

my $status = 'status.txt';

my $hashref = XMLin($status,
                    ForceArray => ['In_Stock'],
                    KeyAttr => [],
                    NoAttr => 0,
                    KeepRoot => 1);

my ($root_tag) = keys %$hashref;#Discover the name of that first tag you want to keep

### Status update in hash
foreach(@fruits){
	    $hashref->{$root_tag}->{'data'}->{$_}->{'In_Stock'} = ['true'];
}

### print the update value $status
print XMLout(
        $hashref,
             KeyAttr => [],
             NoAttr => 0,
             RootName => undef,
             OutputFile => $status,
       );

No working for me still. Unfortunately.

Still not working? What do you get in your status.txt file? After running this script that reads the fruit.txt and status.txt files containing the data that you posted, the status.txt file contains the following (on my computer, anyway):

<configuration name="variant" version="2.91.0" xmlns="http://www.fruits.com/xml/confml/2" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <data>
      <apple>
        <In_Stock>true</In_Stock>
      </apple>
      <banana>
        <In_Stock>true</In_Stock>
      </banana>
      <durian>
        <In_Stock>true</In_Stock>
      </durian>
      <grapes>
        <In_Stock>false</In_Stock>
      </grapes>
      <guava>
        <In_Stock>true</In_Stock>
      </guava>
      <jackfruit>
        <In_Stock>false</In_Stock>
      </jackfruit>
      <lychee>
        <In_Stock>true</In_Stock>
      </lychee>
      <melon>
        <In_Stock>true</In_Stock>
      </melon>
      <pineapple>
        <In_Stock>true</In_Stock>
      </pineapple>
      <rambutan>
        <In_Stock>true</In_Stock>
      </rambutan>
    </data>
  </configuration>

How does that not meet your requirement?

Finally working and I get exact output, as expected!
Thanks David.
Actually I was running the code on another PC this time where the XML module was not up-to-date.

Regards
Boshu

Hi David

The solution works perfectly for the first 2 files. However, I applied this code on another file but noticed that in addition to what it was supposed to do, it changed some additional contents and formats in the file.

The file I tried this time is (variant.confml):
===============================================

<configuration name="variant" version="2.91.0" xmlns="http://www.empty.com/xml/confml/2" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <data>
  <yahoo>
      <Enabled>true</Enabled>
    </yahoo>
  <messaging_chat>
      <Enabled>true</Enabled>
    </messaging_chat>
  <socialnetworking_client>
      <Enabled>true</Enabled>
    </socialnetworking_client>
  <thereyougo>
      <Enabled>true</Enabled>
    </thereyougo>
  <internetsearch>
      <Enabled>true</Enabled>
    </internetsearch>
  <islocalizerapp>
      <Enabled>true</Enabled>
    </islocalizerapp>
  <BlankoHomescreen>
      <Plugins extensionPolicy="replace">
        <Uid>0x2000DBA7</Uid>
      <BundleIdentifier>com.ChatClient</BundleIdentifier>
      <TemplateIdentifier>0x2001f489</TemplateIdentifier>
      <LockingStatus>none</LockingStatus>
      </Plugins>
    <Plugins>
        <Uid>0x2000FFBB</Uid>
      <BundleIdentifier>com.movieteasers</BundleIdentifier>
      <TemplateIdentifier>0x2001E1F9</TemplateIdentifier>
      <LockingStatus>none</LockingStatus>
      </Plugins>
    </BlankoHomescreen>
  </data>
</configuration>

The falgs contents are (flags.txt):
====================================
ami
tumi
she


After running the script the output looks like:
===============================================

<configuration name="variant" version="2.91.0" xmlns="http://www.empty.com/xml/confml/2" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <data>
      <BlankoHomescreen>
        <Plugins BundleIdentifier="com.ChatClient" LockingStatus="none" TemplateIdentifier="0x2001f489" Uid="0x2000DBA7" extensionPolicy="replace" />
        <Plugins BundleIdentifier="com.movieteasers" LockingStatus="none" TemplateIdentifier="0x2001E1F9" Uid="0x2000FFBB" />
      </BlankoHomescreen>
      <ami >
        <Enabled>true</Enabled>
      </ami >
      <internetsearch>
        <Enabled>true</Enabled>
      </internetsearch>
      <islocalizerapp>
        <Enabled>true</Enabled>
      </islocalizerapp>
      <messaging_chat>
        <Enabled>true</Enabled>
      </messaging_chat>
      <she>
        <Enabled>true</Enabled>
      </she>
      <socialnetworking_client>
        <Enabled>true</Enabled>
      </socialnetworking_client>
      <thereyougo>
        <Enabled>true</Enabled>
      </thereyougo>
      <tumi >
        <Enabled>true</Enabled>
      </tumi >
      <yahoo>
        <Enabled>true</Enabled>
      </yahoo>
    </data>
  </configuration>

---------
See, right at the beginningm after <data> it has added the following lines

<BlankoHomescreen>
        <Plugins BundleIdentifier="com.ChatClient" LockingStatus="none" TemplateIdentifier="0x2001f489" Uid="0x2000DBA7" extensionPolicy="replace" />
        <Plugins BundleIdentifier="com.movieteasers" LockingStatus="none" TemplateIdentifier="0x2001E1F9" Uid="0x2000FFBB" />
      </BlankoHomescreen>

But it should live all the contents as is, just add new flags and set the value to true only.

Are you able to suggest why it is not working?

Thanks and kind regards,
Boshu

<BlankoHomescreen>
        <Plugins BundleIdentifier="com.ChatClient" LockingStatus="none" TemplateIdentifier="0x2001f489" Uid="0x2000DBA7" extensionPolicy="replace" />
        <Plugins BundleIdentifier="com.movieteasers" LockingStatus="none" TemplateIdentifier="0x2001E1F9" Uid="0x2000FFBB" />
      </BlankoHomescreen>

These tags are in your variant.confml file in a different position in a slightly different format. I can't control where in the file the tags appear but that shouldn't matter. However you should be able to preserve the original format of those tags by adding them to the ForceArray parameter of the XMLin, as follows.

my $hashref = XMLin($conf,
                    ForceArray => [qw(Enabled
                                   BundleIdentifier
                                   TemplateIdentifier
                                   LockingStatus)],
                    KeyAttr => [],
                    NoAttr => 0,
                    KeepRoot => 1);
This article has been dead for over six months. Start a new discussion instead.