PHP - извлекает правильные значения XML, если элементы имеют похожие теги на запись - PullRequest
0 голосов
/ 16 декабря 2018

PHP - Получить правильные значения XML, если элементы имеют похожие теги на запись

Я получаю следующий XML-файл:

XML-файл:

<?xml version='1.0' encoding='UTF-8'?>
<abc:ABCData xmlns:abc="http://www.abc-example.com" xmlns:xyz="http:/www.xyz-example.com">
<abc:ABCRecords>
 <abc:ABCRecord>
 <abc:ABC>5EXZX4LPK</abc:ABC>
  <abc:Entity>
    <abc:Name>I Bornheim</abc:Name>
    <abc:Periods>
      <abc:Period>
        <abc:Start>2017-01-01</abc:Start>
        <abc:End>2017-12-31</abc:End>
        <abc:Type>ACCOUNTING</abc:Type>
      </abc:Period>
      <abc:Period>
        <abc:Start>2007-09-01</abc:Start>
        <abc:Type>RELATIONSHIP</abc:Type>
      </abc:Period>
    </abc:Periods>      
  </abc:Entity>
</abc:ABCRecord>
<abc:ABCRecord>
  <abc:ABC>5967007LI</abc:ABC>
  <abc:Entity>
    <abc:Name>SUN BANK</abc:Name>
    <abc:Periods>
      <abc:Period>
        <abc:Start>2018-01-01</abc:Start>
        <abc:End>2018-12-31</abc:End>
        <abc:Type>BALANCED</abc:Type>
      </abc:Period>
      <abc:Period>
        <abc:Start>2008-09-01</abc:Start>
        <abc:Type>PARENT</abc:Type>
      </abc:Period>
    </abc:Periods>          
  </abc:Entity>
</abc:ABCRecord>
</abc:ABCRecords>
</abc:ABCData>

... с помощью этого скрипта я вывожу значения в виде csv:

PHP-файл:

<?php

$reader = new XMLReader();
$reader->open('php://stdin');

$output = fopen('php://stdout', 'w');
fputcsv($output, ['id', 'name']);

$xmlns = [
  'abc' => 'http://www.abc-example.com'
];

$dom   = new DOMDocument;
$xpath = new DOMXpath($dom);
foreach ($xmlns as $prefix => $namespaceURI) {
  $xpath->registerNamespace($prefix, $namespaceURI);
}

while (
  $reader->read() && 
  (
    $reader->localName !== 'ABCRecord' || 
    $reader->namespaceURI !== $xmlns['abc']
  )
) {
  continue;
}

while ($reader->localName === 'ABCRecord') {
  if ($reader->namespaceURI === 'http://www.abc-example.com') {
    $node = $reader->expand($dom);
    fputcsv(
      $output, 
      [
        $xpath->evaluate('string(abc:ABC)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Name)', $node)
      ]
    );
  }

  $reader->next('ABCRecord');
} 

... вот так:

Вывод:

5EXZX4LPK,"I Bornheim"
5967007LI,"SUN BANK"

Пока что ... как мне получить правильные значения 'period', если каждая запись периода имеет одно и то же определение тега?

Желаемый результат:

5EXZX4LPK,"I Bornheim",2017-01-01,2017-12-31,"ACCOUNTING",2007-09-01,"RELATIONSHIP"
5967007LI,"SUN BANK",2018-01-01,2018-12-31,"BALANCED",2008-09-01,"PARENT"

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

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

$xpath->evaluate(
    'string(
        abc:Entity/abc:Periods/abc:Period[
            abc:Type = "ACCOUNTING" or abc:Type="BALANCED"
        ][1]/abc:Type
    )', 
    $node
),

Или проверить, есть ли здесь дочерний элемент abc:End:

$xpath->evaluate(
    'string(
        abc:Entity/abc:Periods/abc:Period[
            count(abc:End) = 0
        ][1]/abc:Type
    )', 
    $node
),
0 голосов
/ 16 декабря 2018

Вы можете просто использовать индексную нотацию XPath;думайте об элементах <abc:Period> как о массиве.Помните, что индексы XPath основаны на единицах, а не на нулях.

...
    fputcsv(
      $output, 
      [
        $xpath->evaluate('string(abc:ABC)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Name)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Periods/abc:Period[1]/abc:Start)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Periods/abc:Period[1]/abc:End)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Periods/abc:Period[1]/abc:Type)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Periods/abc:Period[2]/abc:Start)', $node),
        $xpath->evaluate('string(abc:Entity/abc:Periods/abc:Period[2]/abc:Type)', $node),
      ]
    );
...

Вывод:

id,name
5EXZX4LPK,"I Bornheim",2017-01-01,2017-12-31,ACCOUNTING,2007-09-01,RELATIONSHIP
5967007LI,"SUN BANK",2018-01-01,2018-12-31,BALANCED,2008-09-01,PARENT
...