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

时间:2018-11-23 15:23:54

标签: perl xpath xml-libxml

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

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

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

我要实现的目标:
我正在搜索许多不同年龄的xlsx电子表格文档,以查找某些公式并对其进行处理。 我希望只使用一个简单的findnodes(//f)来收集每个工作表中的所有公式。 所有工作表都定义了多个名称空间,但是大多数元素似乎没有完全限定的名称空间。例如:

<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传递所有内容,但希望能够正确解析它不会太难...

2 个答案:

答案 0 :(得分:3)

您可以使用local-name()完全忽略名称空间:

...->findnodes('//*[local-name()="f"]')

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

答案 1 :(得分:1)

没有 the 默认名称空间。标签之间的默认值可以不同。您实际上是在询问根元素的名称空间。您想要这样做以支持一些“足够相似”的格式,它的操作如下:

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)