【问题标题】:Perl libXML search the default namespace using findnodesPerl libXML 使用 findnodes 搜索默认命名空间
【发布时间】:2018-11-23 15:23:53
【问题描述】:

给定一个定义了多个命名空间的 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 管道传输所有内容,但希望正确解析它不会太难...

【问题讨论】:

  • 默认命名空间只存在于语法中。在 DOM 模型中,每个元素都属于一个命名空间,没有办法检测它是否是默认的——事实上,具有默认命名空间的文档和每个元素明确提到的具有相同命名空间的文档在语义上是一致的相等的。为什么需要它?
  • 嗯,好的,我将在问题中添加更多上下文...
  • findnodes('//*[local-name()="f"]') 返回什么?其他命名空间中是否有您不想要的 fs?
  • 谢谢@choroba - 如果我确实拾取额外的元素(即使它们是垃圾)对我的用例来说并不重要,因为我稍后会进一步处理这些元素。无论如何,使用该 XPath 语法对我有用 - 随时将其粘贴为答案:)

标签: perl xpath xml-libxml


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢 choroda - 我明白为什么这不是理想的解决方案,但在我的用例中,我只是想看看 excel 电子表格中的特定函数被使用了多少次(并且只会需要运行一次...)
【解决方案2】:

没有像 默认命名空间这样的东西。默认值可能因标签而异。您实际上是在询问根元素的命名空间。您希望这样做以支持一些“足够相似”的格式,并按如下方式完成:

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2023-03-16
    相关资源
    最近更新 更多