Perl: невозможно извлечь значение родного брата с использованием синтаксиса Twig :: XPath - PullRequest
2 голосов
/ 28 апреля 2020

Недавно я начал использовать XML :: Twig :: XPath, но модуль, похоже, не распознает синтаксис xpath. В следующем XML я хочу получить значение узла "Txt", если значение узла PlcAndNm равно "ext_1"

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <Document>
    <RedOrdrV03>
      <MsgId>
      <Id>1</Id>
      </MsgId>
      <Xtnsn>
        <PlcAndNm>ext_1</PlcAndNm>
        <Txt>1234</Txt>
      </Xtnsn>
      <Xtnsn>
        <PlcAndNm>ext_2</PlcAndNm>
        <Txt>ABC</Txt>
      </Xtnsn>
    </RedOrdrV03>
  </Document>
  <Document>
    <RedOrdrV03>
      <MsgId>
      <Id>2</Id>
      </MsgId>
      <Xtnsn>
        <PlcAndNm>ext_1</PlcAndNm>
        <Txt>9876</Txt>
      </Xtnsn>
      <Xtnsn>
        <PlcAndNm>ext_2</PlcAndNm>
        <Txt>DEF</Txt>
      </Xtnsn>
    </RedOrdrV03>
  </Document>
</root>

Я пробовал выражение whit // Xtnsn [PlcAndNm = " ext_1 "] / Txt но я получил ошибку Это код:

use XML::Twig::XPath;
my $subelt_count = 1;
my @processed_elements;
my $xmlfile = 'c:/test_file.xml';
my $parser = XML::Twig->new(
 twig_roots    => { 'RedOrdrV03' => \&process_xml } ,
 end_tag_handlers => { 'Document' },
);

$parser->parsefile($xmlfile);

sub process_xml {
  my ( $twig, $elt ) = @_;
  push( @processed_elements, $elt );

  if ( @processed_elements >= $subelt_count ) {
    my $MsgId = $twig->findvalue('RedOrdrV03/MsgId/Id');
    my $Xtnsn_Txt1 = $twig->findvalue('//Xtnsn[PlcAndNm="ext_1"]/Txt');
    print "MsgId: $MsgId - Xtnsn_Txt1: $Xtnsn_Txt1\n";
  }
  $_->delete for @processed_elements;
  @processed_elements = ();
  $twig->purge;
}

Есть ли простой способ использования xpath для получения значения? Я знаю, что такая возможность выглядит так:

my $Xtnsn_Txt1 = $twig->first_elt( sub { $_[0]->tag eq 'PlcAndNm' && $_[0]->text eq 'ext_1' })->next_sibling()->text();

, но я предпочитаю использовать простейший синтаксис XPath,

Заранее спасибо за вашу помощь!

Ответы [ 2 ]

3 голосов
/ 28 апреля 2020

Вы можете использовать это:

my $Xtnsn_Txt1 = $twig->findvalue('//Xtnsn/PlcAndNm[string()="ext_1"]/../Txt');
1 голос
/ 28 апреля 2020

Другой подход может быть следующим:

//Txt[preceding-sibling::PlcAndNm[.="ext_1"]]

Вы также можете немного изменить выражение XPath, чтобы посмотреть, работает ли оно с:

//Xtnsn[./PlcAndNm[contains(.,"ext_1")]]/Txt

РЕДАКТИРОВАТЬ: Это отлично работает с оригинальный XML :: Модуль XPath:

use XML::XPath;
use XML::XPath::Node::Element;

my $xp = XML::XPath->new(filename => 'pathtoyour.xml');

my $nodeset = $xp->find('//Xtnsn[PlcAndNm="ext_1"]/Txt');

foreach my $node ($nodeset->get_nodelist) {
    print XML::XPath::Node::Element::string_value($node),"\n\n";
}

Вывод: 1234 9876

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...