Perl: как последовательно анализировать XML-файл - PullRequest
4 голосов
/ 24 декабря 2011

У меня есть файл XML, который описывает структуру данных, которую я могу обмениваться по каналу UDP. Например: Вот мой входной XML-файл, описывающий мою структуру данных.

<ds>
 <uint32 name='a'/>
 <uint32 name='b'/>
 <string name='c'/>
 <int16 name='d'/>
 <uint32 name='e'/>
</ds>

Синтаксический анализ этого XML-файла с помощью Perl XML: просто, позволяет мне сгенерировать следующий хеш

$VAR1 = {
          'uint32' => {
                      'e' => {},
                      'a' => {},
                      'b' => {}
                    },
          'int16' => {
                     'name' => 'd'
                   },
          'string' => {
                      'name' => 'c'
                    }
        };

Как видите, после разбора у меня нет возможности выяснить, какова будет относительная позиция поля 'e' относительно начала структуры данных.

Я бы хотел выяснить смещения каждого из этих элементов.

Я попытался найти анализатор perl XML, который позволяет мне последовательно анализировать XML-файл, что-то вроде функции getnexttag (), но не смог найти.

Каков наилучший способ сделать это программно? Если не Perl, то какой другой язык лучше всего подходит для этой работы?

Ответы [ 3 ]

3 голосов
/ 24 декабря 2011

Вам нужно будет использовать потоковый анализатор с соответствующими обратными вызовами, это также улучшит скорость синтаксического анализа (и даст вам меньшее потребление памяти, если все сделано правильно), когда дело доходит до больших наборов данных, что хорошо / удивительно вещь.

Я рекомендую использовать XML::SAX, введение в модуль доступно по следующей ссылке:

Обеспечивает обратные вызовы для start_element, так что вы можете читать значение каждого элемента по одному за раз.


Не могли бы вы написать простой пример?

Да, и у меня уже есть!; -)

В приведенном ниже фрагменте будут проанализированы предоставленные данные OP и напечатано имя каждого элемента, а также атрибуты ключ / значение.

Это должно бытьдовольно легко понять, но если у вас есть какие-либо вопросы, не стесняйтесь добавлять их в качестве комментария, и я обновлю этот пост более подробной информацией.

use warnings;
use strict;

use XML::SAX;

my $parser = XML::SAX::ParserFactory->parser(
  Handler => ExampleHandler->new
);

$parser->parse_string (<<EOT
<ds>
  <uint32 name='a'/>
  <uint32 name='b'/>
  <string name='c'/>
  <int16 name='d'/>
  <uint32 name='e'/>
</ds>
EOT
);

# # # # # # # # # # # # # # # # # # # # # # # #

package ExampleHandler;

use base ('XML::SAX::Base');

sub start_element {
  my ($self, $el) = @_;

  print "found element: ", $el->{Name}, "\n";

  for my $attr (values %{$el->{Attributes}}) {
    print "  '", $attr->{Name}, "' = '", $attr->{Value}, "'\n";
  }

  print "\n";
}

output

found element: ds

found element: uint32
  'name' = 'a'

found element: uint32
  'name' = 'b'

found element: string
  'name' = 'c'

found element: int16
  'name' = 'd'

found element: uint32
  'name' = 'e'

Я не удовлетворен XML :: SAX, есть ли другие доступные модули?

Да, есть из чего выбирать.Прочитайте следующий список и выберите тот, который вам подходит для вашей конкретной задачи:


В чем разница между различными методами парсинга?

Я также рекомендую прочитать следующие часто задаваемые вопросы, касающиеся XML-парсинга.Это вызовет за и против использования синтаксического анализатора дерева (такого как XML :: Parser :: Simple) или потокового анализатора:

2 голосов
/ 24 декабря 2011

Это наверняка возможно с Perl.

Вот пример с XML::LibXML:

use strict;
use warnings;
use feature 'say';
use XML::LibXML;

my $xml = XML::LibXML->load_xml( location => 'test.xml' );

my ( $dsNode ) = $xml->findnodes( '/ds' );

my @kids = $dsNode->nonBlankChildNodes;     # The indices of this array will
                                            # give the offset

my $first_kid = shift @kids;                # Pull off the first kid
say $first_kid->toString;                   # "<uint32 name='a'/>"

my $second = $first_kid->nextNonBlankSibling();     
my $third  = $second->nextNonBlankSibling();

say $third->toString;                       # "<string name="c"/>"
1 голос
/ 25 декабря 2011

Вот пример использования XML::Twig

use XML::Twig;

XML::Twig->new( twig_handlers => { 'ds/*' => \&each_child } )
         ->parse( $your_xml_data );

sub each_child {
    my ($twig, $child) = @_;
    printf "tag %s : name = %s\n", $child->name, $child->{att}->{name};
}

Это выводит:

tag uint32 : name = a
tag uint32 : name = b
tag string : name = c
tag int16 : name = d
tag uint32 : name = e
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...