You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl实现移除XML指定key的entry节点并保留原有空行

实现保留原空行的XML entry节点删除功能

优先方案:使用XML解析模块(推荐)

用正则处理XML容易出现各种边界问题(比如CDATA内容、属性顺序变化、嵌套标签干扰),因此推荐使用专业的XML解析模块XML::LibXML来实现,既能精准删除节点,又能保留原文件的空白结构。

依赖安装

先安装XML::LibXML模块:

cpanm XML::LibXML

实现代码

use XML::LibXML;
use File::Slurp;

sub remove_xml_entries {
    my ($filename, @keys) = @_;

    # 读取原始文件内容,保留换行结构
    my $xml_content = read_file($filename);

    # 初始化XML解析器,开启空白保留
    my $parser = XML::LibXML->new({
        preserve_blanks => 1,
        load_ext_dtd => 0,
    });
    my $doc = $parser->parse_string($xml_content);

    # 构建待删除key的哈希集合,提升查找效率
    my %target_keys = map { $_ => 1 } @keys;

    # 遍历所有entry节点
    my $xpc = XML::LibXML::XPathContext->new($doc);
    foreach my $entry ($xpc->findnodes('//entry')) {
        my $entry_key = $entry->getAttribute('key');
        next unless exists $target_keys{$entry_key};

        # 删除节点前后的空白文本节点,避免残留空行
        my $prev_node = $entry->previousSibling;
        while ($prev_node && $prev_node->nodeType == XML_TEXT_NODE && $prev_node->data =~ /^\s*$/) {
            $prev_node->parentNode->removeChild($prev_node);
            $prev_node = $entry->previousSibling;
        }

        my $next_node = $entry->nextSibling;
        while ($next_node && $next_node->nodeType == XML_TEXT_NODE && $next_node->data =~ /^\s*$/) {
            $next_node->parentNode->removeChild($next_node);
            $next_node = $entry->nextSibling;
        }

        # 删除目标entry节点
        $entry->parentNode->removeChild($entry);
    }

    # 生成保留原始格式的XML并写入文件
    write_file($filename, $doc->toString(1));
}

代码说明

  • preserve_blanks => 1:让解析器保留原始的空白节点,确保原文件的空行不会被破坏
  • 删除目标节点时,同时清理其前后的空白文本节点,避免删除后残留空行
  • 用XPath精准定位所有entry节点,不受属性顺序或节点格式影响

备选方案:改进正则实现(仅限简单XML场景)

如果不想依赖XML模块,可以使用改进后的正则,但仅适用于结构简单、无嵌套干扰的XML文件:

use File::Slurp;

sub remove_entries_with_regex {
    my ($filename, @keys) = @_;

    my $file_content = read_file($filename);

    # 构建匹配待删除key的正则,转义特殊字符避免匹配错误
    my $key_pattern = join('|', map { quotemeta($_) } @keys);
    # 匹配目标entry节点及其直接关联的空白,不影响其他空行
    $file_content =~ s/^\s*<entry\s+key\s*=\s*"($key_pattern)"[^>]*>.*?<\/entry>\s*$//gms;

    write_file($filename, $file_content);
}

正则说明

  • gms修饰符:全局匹配、多行模式(让^和$匹配每行首尾)、点号匹配换行符
  • 仅删除entry节点及其前后的空白,不会触碰文件中其他位置的空行
  • 局限性:无法处理属性顺序变化、CDATA中包含类似标签、节点嵌套复杂的情况

内容的提问来源于stack exchange,提问作者Kautuk Raj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:59:59