Home
TeamSite
change one field in dcr with perl script
kellyrmilligan
Hello,
I am on TS 6.1, Solaris.
I want to go through a directory of dcrs, compare two date fields, and change one of them if the two fields are equal. What is the recommended approach to do this? A while back I wrote a monster perl script to do some converting of dcrs, but had to get every field, do the magic, and create/delete files, etc, and it was messy. Is there something that just allows you to go in and change one field programmatically?
Thanks,
Kelly
Find more posts tagged with
Comments
Michael
Hi Kelly
Creating a quick Perl script is probably going to be the easiest way.
You can leverage off TeamSite:
irwalk and TeamSite::XMLnode modules so you shouldn't need to write much code at all.
Personally I think Perl is great for just the sort of task you have described!
Good luck with it
Cheers
Michael
jbonifaci
Kelly, completely untested, but you could do something like this:
use strict;
# define an array with all directories to scan for dcrs to convert
my
@Directories
=
(
'Y:/Store/main/Branch/WORKAREA/workarea/templatedata/category/datatype1/data',
'Y:/Store/main/Branch/WORKAREA/workarea/templatedata/category/datatype2/data'
);
# process each path in the directory array.
foreach my $path (
@Directories)
{
&processPath($path);
}
# script has finished, exit.
exit(0);
# If the path is a file, check to see if it is a dcr, if so, convert it.
# If it is a directory, get the contents and process those paths.
sub processPath
{
my ($path) =
@_
;
if (-f $path)
{
my $dcrType = `iwextattr -g TeamSite/Templating/DCR/Type "$path"`;
if ($dcrType !~ /^\s*$/)
{
&convertDcr($path);
}
}
else # directory
{
opendir(SOURCE, $path);
my
@nodes
= readdir SOURCE;
closedir(SOURCE);
foreach my $node (
@nodes)
{next if $node =~ /^\.\.?$/; &processPath("$path\\$node")};
}
}
# get the two dates from the dcr, check if they are equal and if so,
# change one of the dates.
sub convertDcr
{
my ($dcrPath, $dcrType) =
@_
;
unless (open(DCR, "<$dcrPath"))
{
# log error
}
else
{
my $dcrModified = 0;
# read the contents of the dcr in.
my $dcrContent = "";
{
local $/;
$dcrContent = <DCR>;
close(DCR);
}
#retrieve the value of each date field
my $dateFieldOne = &getSingleItemValue(\$dcrContent, 'dateFieldOne');
my $dateFieldTwo = &getSingleItemValue(\$dcrContent, 'dateFieldTwo');
# if both date fields have values, compare them to see if they are the same.
# If so, change one of the dates.
if (($dateFieldOne =~ /^\s*$/) || ($dateFieldTwo =~ /^\s*$/))
{
# log error
}
elsif ($dateFieldOne eq $dateFieldTwo) # or the date comparison method of your choice
{
my $newDate = '';
&setSingleItemValue(\$dcrContent, 'dateFieldTwo', $newDate);
$dcrModified = 1;
}
else
{
# do nothing?
}
# only write the dcr if it has been modified
if ($dcrModified)
{
unless (open(DCR, ">$dcrPath"))
{
# log error
}
else
{
print DCR $dcrContent;
close(DCR);
}
}
}
}
# get the value of an item with a single value
sub getSingleItemValue
{
my ($contentRef, $itemName) =
@_
;
my ($itemValue) = ($$contentRef =~ /<item name=\"$itemName\"[^>]*>\s*<value>((.|\n)*?)<\/value>\s*<\/item>/);
return($itemValue);
}
# set the value of an item with a single value
sub setSingleItemValue
{
my ($contentRef, $itemName, $itemValue) =
@_
;
$$contentRef =~ s/(<item name=\"$itemName\"[^>]*>\s*<value>)(?:.|\n)*?(<\/value>\s*<\/item>)/$1$itemValue$2/;
}
Let me know if you have any questions.
~Jeff
kellyrmilligan
I am sort of doing something similar, except that I thought using the xml parser would do the trick..
so I get the values, and try and set the values ,but am not sure how to put that into the file.
$xml = "";
if (open(DCR, "<$dcrlocation"))
{ local $/;
$xml = <DCR>;
close(DCR);
}else
{
logthis "could not open $dcrlocation";
}
$rootnode = TeamSite::XMLnode->new($xml);
my $expirationdate = $rootnode->get_inner_xml('EXPIREDATE');
my $endDate = $rootnode->get_inner_xml('END_DATE');
$rootnode->set_inner_xml('EXPIREDATE', '2030-12-30');
This is all working, except it doesn't change the physical file, is there some last step like
$rootnode->changephysicalfile
or something I need to do?
cliffhanger
You need to do something like the following to write back to the physical file(your DCR):
open (WRITEFILE, ">$dcrlocation") ;
print WRITEFILE $rootnode->get_dcr();
close WRITEFILE;
border_cut.zip
kellyrmilligan
Couldn't parse DCR bytes into DOM [unable_to_parse_dcr ]:The processing instruction target matching "[xX][mM][lL]" is not allowed.
Getting this message now after I try to open the file in teamsite, I am working off of test data of course...
my $expirationdate = $rootnode->get_inner_xml('EXPIREDATE');
my $endDate = $rootnode->get_inner_xml('END_DATE');
$rootnode->set_inner_xml('EXPIREDATE', '2030-12-30');
my $ofile = "/$mount/$typesection/data/$dcr";
logthis " ofile = $ofile\n";
open FILE, ">>$ofile";
print FILE $rootnode->get_dcr();
chmod 0777, $ofile;
close FILE;
my $result = setTemplatingEAs(DCR=>$ofile,Type=>$cat_type);
any ideas?
piegradient.jpg
PieSliceGradientPalette.rptdesign
cliffhanger
open FILE, ">>$ofile";
Shouldn't you be overwriting rather than appending?
Try
"open FILE, ">$ofile";
kellyrmilligan
yes, you are correct...doh!!!!!
kellyrmilligan
sweet!!! it works, I am attaching the script for posterity!!
kellyrmilligan
Root cause:
Couldn't parse DCR bytes into DOM [unable_to_parse_dcr ]:Invalid byte 1 of 1-byte UTF-8 sequence.
I am getting this error when trying to open up some of the dcr's in teamsite, any ideas?
I am getting this in Std out when I run the script sometimes
Wide character in print at /usr/iw-home/custom/bin/change_one_field_dcr.ipl line 114
and that is where I call
print FILE $rootnode->get_dcr();
any ideas?
mngmntconsole.zip
herald10
Can you open the DCR in vi editor and see if there are any weird characters? Or you can download the DCR to the local machine and open it up in Internet Explorer and check it.
HTH
-H
kellyrmilligan
not seeing any weird characters to speak of, but that might explain why some are working and some are not. I have downloaded them onto my machine and they look fine in IE, valid xml.
herald10
Check this out:
http://devnet.interwoven.com/forums/cgi-bin/showflat.pl?Cat=&Board=PRODUCTS_TEMPLATING&Number=57521&page=&view=&sb=&o=&vc=1
kellyrmilligan
This did work, thanks! But now I have another interesting issue. After I send it to the encodetoUTF fucntion mentioned in the link you posted, the value of the node has to be set, so I do this:
$rootnode->set_inner_xml('CONTENT_POLICY',$policy);
After I do this, the content in this node has ">" signs in it instead of >
so for <p> tags, it shoudl say <p>
Up until the point of setting the node value, I have printed the variable out to a log and it is fine. I then ran a test through and did get_inner_xml after setting it, and that is when the ">"'s started showing up.
Any ideas?
kellyrmilligan
something is still messed up, I tried some regex's etc, but nothing works. still have > signs everywhere, so I am going in and hitting save. Does anyone have a working script in 6.1 to do this?
kellyrmilligan
Here's the script attached if anyone is bored and wants to debut.
Adam Stoller
From a quick glance at your script - try changing the modifier on all your regex's from 'g' to 'gsm' and see if that fixes the problem.
Note however - you're assuming that the '>' is causing problems - you probably have to look for '<', '>' and '&' and perhaps some other characters too - I believe there are some encoding functions in various perl modules that you might be able to use more effectively - however it's up to you to find and investigate them as you wish.
--fish
Senior Consultant, Quotient Inc.
http://www.quotient-inc.com
allDeviceAlarmsReport.rptdesign
jbonifaci
Seems like you're having to do way too much work just to convert those 2 date fields. Perhaps you should look into the script I wrote above? It was untested, but it should work and execute faster than what you're trying to do.