2013-05-08 65 views
2

我在目錄中有幾個名爲TC_Circle1TC_Circle2,`TC_Point1等的XML文件,我想用腳本更新每個文件中的開始和結束日期。開始日期和結束日期在每個文件內部和標籤中。需要在Linux中使用Perl腳本修改幾個XML文件env

我在使用Sun機器時遇到了一個腳本,但它不適用於新的HP Linux機器。它不顯示任何錯誤並且不會更改日期。我需要幫助讓它在Linux中工作。該腳本:

#!/usr/local/bin/perl 
$numArgs = @ARGV; 
if ($numArgs != 2) 
{ 
print "Usage: replace_default_date.pl DEFAULT_START_DATE DEFAULT_STOP_DATE\n"; 
} 

@filenames = `ls TC*`; 
chomp(@filenames); 
foreach $file (@filenames) 
{ 
    open(REGFILE, "$file") || die "Cannot open |$file|"; 
    @lines = <REGFILE>; 
    close(REGFILE); 

    open(WRITEFILE), ">$file") || die "Cannot open |$file|"; 

    foreach $line (@lines) 
    { 
    if ($line =~ /DEFAULT_START_DATE/) 
    { 
     $newline = " " . $ARGV[0]; 
     print WRITEFILE "$newline\n"; 
    } 
    elsif ($line =~ /DEFAULT_STOP_DATE/) 
    { 
     $newline = " " . $ARGV[1]; 
     print WRITEFILE "$newline\n"; 
    } 
    else 
    { 
     print WRITEFILE "$line\n"; 
    } 
    } 
    close (WRITEFILE); 
} 

這裏的文件怎麼修改一下開頭:提前

<RequestSomething xmlns="http://something.com/accessservice"> 
    <period xmlns=""> 
    <start>2013-03-06T00:00:00</start> 
    <stop>2013-03-07T00:00:00</stop> 
    </period> 
    ... The rest of the xml file... 
</RequestSomething> 

感謝, 水晶

+0

你能告訴我們一個(簡短的!)輸入數據的例子嗎? – mirod 2013-05-08 16:29:18

+1

非常危險。如果此程序在開始寫入後死亡,則會丟失文件。它應該寫入臨時文件然後替換。 – stark 2013-05-08 16:34:51

+0

該腳本寫得相當不錯,並且不會將這些文件視爲XML。它也不會在同一個文件上運行兩次。你確定原文有單引號的「ls TC *」,而不是反引號,這將需要將字符串作爲shell命令運行? – amon 2013-05-08 16:39:41

回答

0

既然你想要做的是比較簡單的,你並不是真的需要將它視爲一個.xml文件。我會像你一樣對待它,以避免混淆。對於你這樣做的方式,似乎Tie :: File是一個很好的選擇。例如:

的test.xml:

<RequestSomething xmlns="http://something.com/accessservice"> 
    <period xmlns=""> 
    <start>2013-03-06T00:00:00</start> 
    <stop>2013-03-07T00:00:00</stop> 
    </period> 
    ... The rest of the xml file... 
</RequestSomething> 

代碼:

use Tie::File; 
use strict; 
use warnings; 

my @ra=(); 
tie @ra, 'Tie::File', "test.xml" or die; 
my $length=scalar(@ra); 

for (my $i=0; $i < $length; $i++) 
{ 
    if ($ra[$i] =~ /(\s*)<start>.*<\/start>/) 
    { 
     $ra[$i]="$1<start>$ARGV[0]<\/start>"; 
    } 
    elsif ($ra[$i] =~ /(\s*)<stop>.*<\/stop>/) 
    { 
     $ra[$i]="$1<stop>$ARGV[1]<\/stop>"; 
    } 
} 

使用領帶::文件,你可以進入你的文件,並使用數組訪問/修改其內容。 (\s*)<stop>.*<\/stop>基本上做到以下幾點:(\ s *)將所有空間提取到$ 1之前。 <stop>.*<\/stop>查找在它們之間具有任何一組非換行符的停止標籤。一旦我們知道我們處於正確的位置,我們只需通過修改數組來更改該行,正如我所說的那樣直接更改文件。我們在那裏放置1美元來保存縮進。

這裏的時候,我的perl執行凌晨1點test.pl下午新的test.xml:

<RequestSomething xmlns="http://something.com/accessservice"> 
    <period xmlns=""> 
    <start>1am</start> 
    <stop>2pm</stop> 
    </period> 
    ... The rest of the xml file... 
</RequestSomething> 

您可以添加要經過所有必需的文件的選項,只要確保每一個文件之後,重置你的數組,即@ ra =();祝你好運。希望這可以幫助!

編輯:看看對解開陣列的評論,你也應該這樣做。

+0

PS:不知道你對perl有多熟悉,但是如果你沒有安裝Tie :: File,這是行不通的。要安裝它,只需進入cmd或終端並通過鍵入「cpan」(不包括引號)來打開cpan shell。打開cpan後鍵入:「install Tie :: File」並按回車。然後你的perl模塊將自行安裝。 – 2013-05-08 17:14:18

+1

我認爲最好總是'解開@ array'。 – chrsblck 2013-05-08 17:30:19

+0

雖然OP從'cpan'安裝東西,但現在是安裝「XML」解析器的好時機。例如。 'XML :: LibXML'或['XML :: Parser'](http://search.cpan.org/~msergeant/XML-Parser-2.36/Parser.pm)。 – chrsblck 2013-05-08 17:33:05

1

腳本有幾個問題。

1)是因爲一個額外的右括號的編譯錯誤:

開放(WRITEFILE), 「> $文件」)||死「無法打開| $文件|」;

應當書面方式爲

開放(WRITEFILE, 「> $文件」)||死「無法打開| $文件|」;

2)你應該在

@filenames = 'ls TC*'; 

使用反引號,而不是單引號,否則@filenames將只包含字符串「LS TC *」,而不是文件名的實際列表:

@filenames = `ls TC*`; 

3)你確定perl解釋器的路徑是/usr/local/bin/perl? (從命令行嘗試which perl以檢查路徑)。如果不是,那麼第一行應該改變。因爲它被設計來取代包含字符串的行

4)該腳本將永遠不會對XML數據的工作,你向我們展示DEFAULT_START_DATEDEFAULT_STOP_DATE(與提供的腳本變量的日期)。這些字符串不會顯示在您向我們顯示的數據中。

但是,如果XML文件是這樣的腳本將工作:

<RequestSomething xmlns="http://something.com/accessservice"> 
    <period xmlns=""> 
     <start> 
      DEFAULT_START_DATE  
     </start> 
     <stop> 
      DEFAULT_STOP_DATE 
     </stop> 
    </period> 
    ... The rest of the xml file... 
</RequestSomething> 

我希望這將有助於你得到它的工作,但無論如何,我會建議你重寫,因爲它的腳本使用非常不可靠且危險的方式更改XML文件。

0

爲什麼不使用XML解析器?你不能從那臺機器上的CPAN進行安裝嗎?

如果文件不大,您可以使用XML::Simple,否則請使用XML::Twig - 儘管如果您不習慣回調處理程序可能會非常棘手。

我用XML::XPath向您展示了一個簡單的方法。

use XML::XPath; 
use DateTime; 

my $xp = XML::XPath->new(filename => 'input.xml'); 

$xp->setNodeText('/RequestSomething/period/start', DateTime->now->strftime("%FT%T")); 
$xp->setNodeText('/RequestSomething/period/stop', DateTime->now->add(days=>1)->strftime("%FT%T")); 

open my $fh, '>', 'output.xml' or die "$!"; 
print $fh $xp->getNodeAsXML(); 
close $fh; 

我用DateTime設置當前日期,但你當然可以沒有它。