Perl libXML 使用 findnodes 搜索默认命名空间

Perl libXML search the default namespace using findnodes

给定一个定义了多个命名空间的 XML 文件,使用 XPath 查询在默认命名空间中搜索 DOM 元素的最简单方法是什么?

如标题所示,这是使用 Perl 和 libXML。

此外,是否可以在不硬编码命名空间的情况下执行此操作(如果使用 XPathContext 定义命名空间是否可以查询文件的默认命名空间)

我要实现的目标:
我在许多不同年代的 xlsx spreadsheet 文档中搜索某些公式并进行处理。 我打算只使用一个简单的 findnodes(//f) 来收集每个 sheet 中的所有公式。 所有 sheet 都定义了多个命名空间,但大多数元素似乎没有完全限定的命名空间。例如:

<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
<sheetData>
    <row r="1">
        <c r="A1">
            <f>SUM(1+2)</f>
            <v>3</v>
        </c>
        <c r="A2">
            <f>SUM(4+5)</f>
            <v>9</v>
        </c>
...
<controls>
    <mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
        <mc:Choice Requires="x14">
            <control shapeId="1" r:id="rId4" name="blah">
...

正如我上面提到的,我只关心公式,即:在上面的示例中 "SUM(1+2)" 和 "SUM(4+5)"。

我怎样才能提取出这些数据?
解决方案不一定非常漂亮,但它必须始终有效(我不确定命名空间是否变化很大。)

我可以通过 grep/sed 传递所有内容,但希望正确解析它不会太难...

您可以使用 local-name():

完全忽略命名空间
...->findnodes('//*[local-name()="f"]')

请注意,一般来说,这不是最好的主意。例如,如果公式的语法取决于版本并且您需要对其进行规范化,您将分别在每个命名空间中搜索公式,并根据命名空间 运行 不同的转换。

没有 默认命名空间这样的东西。默认值可能因标签而异。您实际上是在请求根元素的名称空间。您希望这样做是为了支持一些 "similar enough" 格式,其完成方式如下:

use XML::LibXML               qw( );
use XML::LibXML::XPathContext qw( );

my $doc = XML::LibXML->new->parse_string($xml);

my $root_ns = $doc->documentElement->namespaceURI;

my $xpc = XML::LibXML::XPathContext->new();
$xpc->registerNs( xl => $root_ns );

$xpc->findnodes('//xl:f', $doc)

但是您没有提出不使用已知命名空间的任何理由。您应该简单地使用以下内容:

use XML::LibXML               qw( );
use XML::LibXML::XPathContext qw( );

my $doc = XML::LibXML->new->parse_string($xml);

my $xpc = XML::LibXML::XPathContext->new();
$xpc->registerNs( xl => 'http://schemas.openxmlformats.org/spreadsheetml/2006/main' );

$xpc->findnodes('//xl:f', $doc)