Perl libXML ищет пространство имен по умолчанию, используя findnodes - PullRequest
0 голосов
/ 23 ноября 2018

Учитывая XML-файл с несколькими определенными пространствами имен, каков самый простой способ поиска элементов в DOM только в пространстве имен по умолчанию с использованием запроса XPath?

Как видно из заголовка, для этого используются Perl и libXML.

Кроме того, возможно ли это сделать без жесткого кодирования пространства имен (если с помощью XPathContext для определения пространства имен можно запросить пространство имен по умолчанию для файла)

What I 'Я пытаюсь достичь:
Я ищу во многих электронных таблицах 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)".

Как я могу извлечь только эти данные?
Решение не должно быть красивым, но оно всегда должно работать (я не уверен, сильно ли меняются пространства имен.)

Iмог бы просто передать все через grep / sed, но надеялся, что при правильном разборе это не будет слишком сложно ...

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Нет такой вещи, как пространство имен по умолчанию.Значение по умолчанию может отличаться от тега к тегу.Вы фактически запрашиваете пространство имен корневого элемента.Вы хотите сделать это для поддержки нескольких «достаточно похожих» форматов, и это делается следующим образом:

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)
0 голосов
/ 23 ноября 2018

Вы можете полностью игнорировать пространства имен с помощью local-name():

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

Обратите внимание, что в целом это не лучшая идея.Например, если синтаксис формул зависит от версии и вам необходимо их нормализовать, вы должны искать формулы в каждом пространстве имен отдельно и запускать различные преобразования на основе пространства имен.

...