在Perl中从XML文件中删除具有特定键的条目

ipakzgxi  于 10个月前  发布在  Perl
关注(0)|答案(2)|浏览(96)

XML文件看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<!-- some comment here -->
<rsccat version="1.0" locale="en_US" product="some_prouduct" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../product/resources/schema/msgcat.xsd">
  <message>

    <entry key="entry1" lol="false">
        <![CDATA[
            <actions>
                <action id="hmm" type="nothing">
                    <cmd>456</cmd>
                    <msg id="123"></msg>
                </action>
            </actions>
        ]]>
    </entry>

<entry key="entry2">message2 </entry>
<entry key="entry3">message3 </entry>

<entry key="entry4">
    <actions hello="yes">
    <action type="lol">
    <cmd>rolf</cmd>
    <txt>omg</txt>
    </action>
    </actions> </entry>


</message>
</rsccat>

字符串
我想用Perl写一个函数,它接受一个XML文件的路径和一个要删除的键的列表,并完全删除与这些键相关的条目,而不留下任何白色或空行。此外,我希望保留原始XML文件中现有的空白行,例如,带有键entry4的条目之后的三个空白行。
我已经编写了一个函数,它删除条目而不留下任何空行,但它也删除了XML文件中现有的空行。

use File::Slurp;  
sub findReplaceFile
{
    my ($filename, @keys) = @_;  

    my $filetext = read_file($filename);

    foreach my $key (@keys) 
    {
        chomp($key);  # remove newline characters
        my $regex = qr/<entry\s+key\s*=\s*"${key}".*?>.+?<\/entry>/s;
        $filetext =~ s/$regex//gs;  # replacing with empty string
        $filetext =~ s/\n\s*\n/\n/g;  # removing extra line
    }
}


请帮助我实现我的目标,我对Perl中的XML解析器模块和普通的正则表达式都很满意。

fxnxkyjh

fxnxkyjh1#

编写了一个不使用模块的示例。最有可能的是,在阅读文件时,他们使用了chomp函数,该函数删除了换行符。这不是最终的事实,只是我的假设。就是这个模块(File::Slurp)我从来没有用过。文件app.pl

#!/usr/bin/perl -w
use strict;

my $path = "data.xml";
findReplaceFile($path, "entry2", "entry4");

sub findReplaceFile {
    my ($filename, @keys) = @_;
    my $data = readData($filename);
    foreach my $key (@keys) {
        $data =~ s/<entry[^>]+key=(.?)$key\1[^>]*?>.*?<\/entry>\n?//mis;
    }
    writeData($filename, $data);
}

sub writeData {
    my $path = shift || "data.txt";
    my $data = shift || die "To write data to a file, you need to transfer this data";
    if (-e $path) {
        open my $fh, ">$path.dat" or die "Can't open file '$path.dat' for write: $!";
        print $fh $data;
        close $fh;
    }
}

sub readData {
    my $path = shift || "data.txt";
    my $data = "";
    if (-e $path and -T $path and -r $path) {
        open my $fh, "<$path" or die "Can't open file '$path' for read: $!";
        $data = join("", <$fh>);
        close $fh;
    } else {
        die "File '$path' dosn't exists or not a text file";
    }
    return $data;
}

字符串
此代码不会修改原始XML。它会将结果保存在一个单独的文件中,并在文件名中添加子字符串“.dat”,如下所示:

open my $fh, ">$path.dat" or die;


还应该注意的是,这段代码完全将文件读入内存,如果你的文件增长到一个巨大的大小,你将需要重写从文件中逐行阅读的算法,以及动态检查和替换。
下面的代码行与上面的代码完全相同。在终端中运行此行,关键号必须在此部分指定:(?:1| 3)-第一和第三(?:1| 3| 2)-第一、第三和第二等。

perl -i.dat -ps0400e "s/<entry[^>]+key=(.?)entry(?:1|3)\1[^>]*?>.*?<\/entry>\n?//gmis" data.xml


现在原始文件将以.dat扩展名保存,结果将以原始名称保存到文件中。

mftmpeh8

mftmpeh82#

回答我自己的问题,为了完成。
感谢@e1st0rm建议使用正则表达式。

use File::Slurp;  
sub findReplaceFile
{
    my ($filename, @keys) = @_;  

    my $filetext = read_file($filename);

    foreach my $key (@keys) 
    {
        $filetext =~ s/<entry[^>]+key=(.?)$key\1[^>]*?>.*?<\/entry>\n?//mis;
    }
    # Now, just write the data in variable filetext into the same or different file
}

字符串

相关问题