如何使用 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。) 完全不相关,但可以节省一些输入:->
是 optional between bracket subscripts,所以你可以改用它:$xml->outer_tag[0]string[0]default = 'New_Name'
【参考方案1】:
XML::Simple
自带following warning:
请不要在新代码中使用此模块
因此,我建议使用另一个模块(例如,XML::Twig
或 XML::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::Dumper
或Data::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::Twig
或XML::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, '>', $xml_file
,那么对于XML::LibXML
,一个简单的print $FH $dom->toString
就可以了。对于XML::Twig
,您可以使用$xml->print($FH)
。以上是关于如何使用 XML::Simple 根据 Perl 中的 XML 属性内容修改 XML 元素?的主要内容,如果未能解决你的问题,请参考以下文章