如何使用XML::LibXML读取带默认命名空间的XML标签?
解决带默认命名空间的XML节点读取问题
哈哈,这个坑我踩过!默认命名空间简直是XPath新手的噩梦,你代码查不到节点的原因很简单:XML里的<Workbook>带了默认命名空间xmlns='urn:schemas-microsoft-com:office:spreadsheet',这意味着它下面的<id>节点也自动属于这个命名空间,但你的XPath查询//id是在无命名空间的节点集合里找目标,自然匹配不到。当你去掉默认命名空间后,所有节点都不属于任何命名空间,查询就正常生效了。
下面给你两种靠谱的解决方法:
方法一:绑定命名空间前缀(推荐)
最清晰的做法是给默认命名空间绑定一个自定义前缀,然后在XPath里用这个前缀定位节点。修改后的代码如下:
use XML::LibXML; my $filename = 'example.xml'; my $dom = XML::LibXML->load_xml( location => $filename ); my $xpc = XML::LibXML::XPathContext->new($dom); # 给默认命名空间绑定前缀(这里用ss当例子,你可以随便取) $xpc->registerNs('ss', 'urn:schemas-microsoft-com:office:spreadsheet'); # 使用前缀查询id节点 my $match1 = $xpc->findnodes('//ss:id'); # 取出节点的文本值并打印 print "XPath result: ", $match1->to_literal, "\n";
这里的核心是registerNs方法,它把默认命名空间的URI和ss前缀关联起来,之后//ss:id就能精准匹配到属于该命名空间的<id>节点了。
方法二:用XPath函数匹配(不推荐)
如果你不想绑定前缀,也可以通过XPath的local-name()和namespace-uri()函数来匹配节点,不过这种写法繁琐且可读性差,适合临时调试用:
use XML::LibXML; my $filename = 'example.xml'; my $dom = XML::LibXML->load_xml( location => $filename ); my $xpc = XML::LibXML::XPathContext->new($dom); # 通过本地名称和命名空间URI匹配节点 my $match1 = $xpc->findnodes('//*[local-name()="id" and namespace-uri()="urn:schemas-microsoft-com:office:spreadsheet"]'); print "XPath result: ", $match1->to_literal, "\n";
这种方式是绕过前缀,直接匹配节点的本地名称(去掉命名空间的部分)和对应的命名空间URI,虽然能生效,但查询多个节点时会非常冗余,所以还是推荐第一种方法。
内容的提问来源于stack exchange,提问作者geofrey rainey
相关产品推荐
相关产品推荐

