如何使用XML::LibXML保留XML字符引用的往返一致性?
问题描述
我在解析包含多个实体的XML文件时,需要修改部分XML属性、值、节点名称后重新保存,但当前处理过程中XML字符引用会被自动解码,输出不符合预期:
XML文件片段
<?xml version="1.0" encoding="UTF-8"?> <root> <copyright-statement>Copyright ©The authors 2024.</copyright-statement> </root>
Perl代码片段
use XML::LibXML; use File::Slurp; open my $fh, '<', $ARGV[0] or die $!; binmode $fh; my $dom = XML::LibXML->load_xml(IO => $fh); my $root = $dom->documentElement(); my @cp = $root->findnodes('//copyright-statement'); write_file('file_name.txt', $cp[0]->textContent);
输出差异
- 期望输出:
Copyright ©The authors 2024. - 实际输出:
Copyright ©The authors 2024.
请问需对上述Perl代码做哪些修改,才能保留原XML字符引用?
解决方案
XML::LibXML的textContent方法会自动解码XML字符引用,要保留原始的字符引用,需要调整XML加载方式和内容获取逻辑:
修改后的代码如下:
use XML::LibXML; use File::Slurp; open my $fh, '<', $ARGV[0] or die $!; binmode $fh; # 加载XML时禁用实体自动展开 my $dom = XML::LibXML->load_xml(IO => $fh, expand_entities => 0); my $root = $dom->documentElement(); my @cp = $root->findnodes('//copyright-statement'); # 获取节点下所有子文本节点的原始内容并拼接 my $raw_content = join '', map { $_->toString() } $cp[0]->childNodes(); write_file('file_name.txt', $raw_content);
修改要点说明
- 禁用实体展开:在
load_xml中添加expand_entities => 0参数,阻止解析器自动解码字符引用。 - 获取原始文本内容:通过
childNodes()遍历目标节点的子节点,调用toString()获取每个文本节点的原始未解码内容,拼接后得到保留字符引用的字符串。
处理后即可得到符合预期的输出。
内容的提问来源于stack exchange,提问作者Prakash Khandelwal
相关产品推荐
相关产品推荐

