Навигация по XML-файлу с использованием XML :: Twig - PullRequest
0 голосов
/ 13 марта 2019

Я должен сказать, что я новичок в Perl и XML: Twig, но я быстро учусь.Буду очень признателен за любую помощь, которую вы можете предоставить.

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

Я использую TwigHandler, чтобы получить доступ к определенному узлу в XML,в частности, узел «Выбор».TwigHandler прекрасно работает для меня в том смысле, что я могу извлечь часть информации, которая мне нужна на этом уровне.Однако в разделе «Выбор» есть дополнительные узлы, которые мне нужно проверить, и я не знаю, как к ним добраться.

Я скопировал фрагмент моего XML ниже, чтобы вы могли видеть, как он выглядит,В нем вы можете увидеть узел выбора.Я могу без проблем получить доступ к атрибуту «id» и полю «Name», используя мой обработчик веток, но мне нужно пройти через все эти узлы «Message» в узле Selection, чтобы извлечь все атрибуты изкаждый из них.Я пытался заставить "get_xpath" работать, но безрезультатно.

Пожалуйста, имейте в виду, что в моем XML-файле есть узлы Message под каждым узлом Selection.В приведенном ниже примере вы видите только 2 узла выбора, но на самом деле у меня могут быть сотни узлов «Выбор», каждый из которых имеет узлы «Сообщение» в качестве дочерних.Мне нужно извлечь информацию из узлов «Сообщение» в текущем узле «Выбор», с которым я работаю, то есть меня не волнуют другие узлы «Сообщения», которые могут находиться под разными узлами «Выбор».

<Selection id="54008473">
  <Name>Master</Name>
  <Contents>
    <Message refid="125796458" suppress="true" status="Unchanged"/>
    <Message refid="123991123" suppress="true" status="Unchanged"/>
    <Message refid="128054778" custom="true" status="New">
      <Content language="en"><![CDATA[<p>ada</p>]]></Content>
    </Message>
  </Contents>
  <Messages/>
  <MessagePriority>
    <Zone name="Insured Letter Intro">
      <MessageInstance id="125796375" name="LD Letter Introduction" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
    </Zone>
    <Zone name="Insured Letter Logo">
      <MessageInstance id="125794623" name="Insured Letter Logo" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
     </Zone>
  </MessagePriority>
</Selection>
<Selection id="54008475" datavaluerefid="54008479">
  <Name>RMBC</Name>
  <Contents>
    <Message refid="125796458" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
    <Message refid="123991123" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
    <Message refid="128054778" custom="true" status="New">
      <Content language="en"><![CDATA[<p>ada</p>]]></Content>
    </Message>
  </Contents>
  <Messages/>
  <MessagePriority>
     ...
  </MessagePriority>
</Selection>

1 Ответ

2 голосов
/ 13 марта 2019

Используйте findnodes() с относительным XPath в обработчике для Selection, чтобы найти Contents/Message дочерние узлы:

#!/usr/bin/perl
use warnings;
use strict;

use XML::Twig;

my %selections;

my $twig = XML::Twig->new(
    twig_handlers => {
        Selection => sub {
            #$_->print();
            print "selection id: ", $_->att('id'), "\n";

            my @messages;
            foreach my $message ($_->findnodes('./Contents/Message')) {
                #$message->print();
                print "message refid: ", $message->att('refid'), "\n";

                # store "refid" attribute in messages list
                push(@messages, $message->att('refid'));
            }

            # store collected Message nodes under selection ID
            $selections{ $_->att('id') } = \@messages;
        },
    }
);

$twig->parse(\*DATA);

while (my($id, $messages) = each %selections) {
    print "Selection '${id}' messages: @{ $messages }\n";
}

exit 0;

__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <Selection id="54008473">
    <Name>Master</Name>
    <Contents>
      <Message refid="125796458" suppress="true" status="Unchanged"/>
      <Message refid="123991123" suppress="true" status="Unchanged"/>
      <Message refid="128054778" custom="true" status="New">
        <Content language="en"><![CDATA[<p>ada</p>]]></Content>
      </Message>
    </Contents>
    <Messages/>
    <MessagePriority>
      <Zone name="Insured Letter Intro">
        <MessageInstance id="125796375" name="LD Letter Introduction" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
      </Zone>
      <Zone name="Insured Letter Logo">
        <MessageInstance id="125794623" name="Insured Letter Logo" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
      </Zone>
    </MessagePriority>
  </Selection>
  <Selection id="54008475" datavaluerefid="54008479">
    <Name>RMBC</Name>
    <Contents>
      <Message refid="125796458" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
      <Message refid="123991123" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
      <Message refid="128054778" custom="true" status="New">
        <Content language="en"><![CDATA[<p>ada</p>]]></Content>
      </Message>
    </Contents>
    <Messages/>
    <MessagePriority>
      ...
    </MessagePriority>
  </Selection>
</Root>

Тестовый прогон:

$ perl dummy.pl
selection id: 54008473
message refid: 125796458
message refid: 123991123
message refid: 128054778
selection id: 54008475
message refid: 125796458
message refid: 123991123
message refid: 128054778
Selection '54008473' messages: 125796458 123991123 128054778
Selection '54008475' messages: 125796458 123991123 128054778
...