使用Perl XML::LibXML移除含指定属性的XML节点标签
如何用Perl的XML::LibXML移除指定XML节点的标签并保留内容?
你遇到的HIERARCHY_REQUEST_ERR错误,根源有两个:
- 用
XML::LibXML->load_xml(string => $nodestring)会生成全新的DOM文档,直接把这个文档节点插入原DOM,违反了XML节点的层级规则; - 你的XPath选择器
//a/b[@class="deletethistag"]/*只选中了目标节点的子元素,漏掉了文本节点,导致最终结果丢失了keep this text这类纯文本内容。
要实现「移除节点标签,保留其所有子内容(文本+子元素)并合并到父节点」的需求,正确的做法是直接移动目标节点的子节点到父节点中,而不是重新解析节点字符串。下面是修正后的代码:
#!/usr/bin/env perl use 5.020; use warnings; use XML::LibXML; # 输入XML my $inputstr = <<XML; <root> <a> <b class="deletethistag">keep this text<c>keep this c node</c>keep this text too</b> <b class="someothertag">don't change this</b> <b>don't change this node without an attribute</b> <c class="type1">don't change this either</c> </a> </root> XML my $dom = XML::LibXML->load_xml(string => $inputstr); # 找到所有需要处理的节点(带class="deletethistag"的b节点) foreach my $target_node ($dom->findnodes(q#//a/b[@class="deletethistag"]#)) { my $parent = $target_node->parentNode(); # 遍历目标节点的所有子节点(包括文本节点和元素节点) foreach my $child (reverse $target_node->childNodes()) { # 将子节点插入到目标节点的前面 $parent->insertBefore($child, $target_node); } # 删除原目标节点 $target_node->unbindNode(); } # 输出结果 say $dom->toString(1);
关键细节说明:
- 用
childNodes()获取目标节点的所有子节点,包括文本节点、元素节点等,避免遗漏内容; - 用
reverse遍历子节点:因为插入节点时,每次插在目标节点前面,正向遍历会导致子节点顺序反转,反向遍历能保持原顺序; - 直接移动原DOM中的节点,不需要重新解析字符串,避免层级错误。
适配你的实际需求
如果你要移除的是<span lang="en" xml:space="preserve">标签,只需要修改XPath选择器即可:
foreach my $target_node ($dom->findnodes(q#//span[@lang="en" and @xml:space="preserve"]#)) { # 后续处理逻辑和上面一致 }
内容的提问来源于stack exchange,提问作者Kwabena
相关产品推荐
相关产品推荐

