如何使用 XML::Simple 根据 Perl 中的 XML 属性内容修改 XML 元素?

Posted

技术标签:

【中文标题】如何使用 XML::Simple 根据 Perl 中的 XML 属性内容修改 XML 元素?【英文标题】:How do I modify an XML element based on XML attribute content in Perl using XML::Simple? 【发布时间】:2021-10-18 10:33:36 【问题描述】:

我有以下格式的 XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<outer_tag>
        <inner_tag name="Name_0" template="Template_0">
        <string name="Name_1"><default>DEFAULT_NAME</default></string>
        <string name="Name_2"><default /></string>
        <string name="Name_3"><default></default></string>
        </inner_tag>
</outer_tag>

我需要修改内容为 "DEFAULT_NAME" 的元素,并且它的父标签属性需要是 "Name_1"。

所以,输出将是这样的:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<outer_tag>
        <inner_tag name="Name_0" template="Template_0">
        <string name="Name_1"><default>**NEW_NAME**</default></string>
        <string name="Name_2"><default /></string>
        <string name="Name_3"><default></default></string>
        </inner_tag>
</outer_tag>

我尝试了以下代码:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Simple;

my $xml_file = 'xml1.xml';

my $xml = XMLin(
    $xml_file,
    KeepRoot => 1,
    ForceArray => 1,
);

$xml->outer_tag->[0]->string->[0]->default = 'New_Name';

XMLout(
    $xml,
    KeepRoot => 1,
    NoAttr => 1,
    OutputFile => $xml_file,
);

但它在末尾添加了 New_Name1,而不是修改我需要替换的那个。我是 Perl 中的 XML 新手。

【问题讨论】:

你试过什么?你有什么问题?请向我们展示您的代码。 (提示:最好的解决方案几乎肯定不使用 XML::Simple。) 完全不相关,但可以节省一些输入:-&gt; 是 optional between bracket subscripts,所以你可以改用它:$xml-&gt;outer_tag[0]string[0]default = 'New_Name' 【参考方案1】:

XML::Simple 自带following warning:

请不要在新代码中使用此模块

因此,我建议使用另一个模块(例如,XML::TwigXML::LibXML)。如果您必须使用XML::Simple,请参阅我回答的结尾。

使用XML::Twig,您可以:

use XML::Twig;

my $xml_file = 'xml1.xml';
my $twig = XML::Twig->new();
$twig->parsefile($xml_file);

my $node = ($twig->get_xpath('/outer_tag/inner_tag/string[@name="Name_1"]/default'))[0];
$node->set_text('New_Name');

$twig->print;

如果需要,您可以缩进输出或打印到文件,请参阅the documentation。

或者,使用XML::LibXML

use XML::LibXML;

my $xml_file = 'xml1.xml';
my $dom = XML::LibXML->load_xml(location => $xml_file);

my $node = ($dom->findnodes('/outer_tag/inner_tag/string[@name="Name_1"]/default/text()'))[0];
$node->setData('New_Name');

print $dom->toString

如果你坚持使用XML::Simple

您当前使用XML::Simple 的代码不起作用的原因是您假设$xml 的结构是什么,而您的假设是错误的。使用Data::DumperData::Printer,您可以轻松检查您的结构包含的内容,问题就很明显了:

use Data::Printer;

my $xml_file = 'xml1.xml';

my $xml = XMLin(
    $xml_file,
    KeepRoot => 1,
    ForceArray => 1,
    );

p $xml;

这将输出:

\ 
    outer_tag   [
        [0] 
            inner_tag   
                Name_0   
                    string     
                        Name_1   
                            default   [
                                [0] "DEFAULT_NAME"
                            ]
                        ,
....

因此很明显你应该这样做

$xml->outer_tag->[0]->inner_tag->Name_0->string->Name_1->default = 'New_Name';

而不是

$xml->outer_tag->[0]->string->[0]->default = 'New_Name';

话虽如此,请使用XML::TwigXML::LibXML

【讨论】:

我尝试了 XML::LibXML 并得到以下错误:Can't call method "setData" on an undefined value at test_xml.pl line 7. 我错过了什么吗? @sbk 当我使用您提供的输入运行它时它可以工作。我的猜测是您的输入文件不是您在问题中粘贴的文件。如果不知道您的数据的实际结构,我无法帮助您。 看起来是环境问题。感谢您的解决方案。它不会替换现有文件吗? @sbk 我提供的 sn-ps 不会替换现有文件,但您可以open 并打印到它。例如,open my $FH, '&gt;', $xml_file,那么对于XML::LibXML,一个简单的print $FH $dom-&gt;toString 就可以了。对于XML::Twig,您可以使用$xml-&gt;print($FH)

以上是关于如何使用 XML::Simple 根据 Perl 中的 XML 属性内容修改 XML 元素?的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中使用 XML::Simple 将哈希转换为 XML 后内容丢失

找不到 XML/Simple.pm

安装的 Perl 模块不可用

为啥 XML::Simple 不受欢迎?

如何使用 Perl 从一组字母中生成单词列表?

XML :: Simple为大型XML返回“Out of memory”错误