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)
给定一个定义了多个命名空间的 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)