XML-разбор PHP - PullRequest
       7

XML-разбор PHP

0 голосов
/ 12 июня 2018

Мне нужно проанализировать этот XML-файл, который имеет несколько пользовательских тегов, как показано здесь:

    <?xml version="1.0" encoding="utf-8"?>
<glz:Config xmlns:glz="http://www.glizy.org/dtd/1.0/">
    <glz:Import src="config.xml" />

    <glz:Group name="thumbnail">
        <glz:Param name="width" value="200" />
        <glz:Param name="height" value="*" />
    </glz:Group>
</glz:Config>

Когда он попадает в тег <glz:Import src="config.xml" />, ему нужно проанализировать файл config.xml , который содержит следующее:

    <?xml version="1.0" encoding="utf-8"?>
<glz:Config xmlns:glz="http://www.glizy.org/dtd/1.0/">
    <glz:Group name="folder">
        <glz:Param name="width" value="100" />
        <glz:Param name="height" value="200" />
    </glz:Group>
</glz:Config>

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

$result['thumbnail/width'] = 200;
$result['thumbnail/height'] = '*';
$result['folder/width'] = 100;
$result['folder/height'] = 200;

Так я справился с разбором XML.Моя проблема в том, что я не знаю, как объединить новые результаты с уже (старыми) проанализированными.Здесь вы можете увидеть мой код:

function parseFile(){
            $reader = new XMLReader;
            $reader->open($this->fileName);

            while ($reader->read()){
                if ($reader->name == 'glz:Group')
                {
                    $groupName = $reader->getAttribute('name');
                    $reader->read();
                    $reader->read();

                    while ($reader->name == 'glz:Param')
                    {
                        if (strpos($reader->getAttribute('name'),'[]')  == true)
                        {
                            $arrayGroupName = substr($reader->getAttribute('name'), 0, -2);
                            if(empty($filters[$groupName.'/'.$arrayGroupName]))
                            {
                                $filters[$groupName.'/'.$arrayGroupName] = array();
                                array_push($filters[$groupName.'/'.$arrayGroupName],$this->castValue($reader->getAttribute('value')));
                                $this->result[$groupName."/".$arrayGroupName] = $filters[$groupName.'/'.$arrayGroupName];
                            }
                            else
                            {
                                array_push($filters[$groupName.'/'.$arrayGroupName],$this->castValue($reader->getAttribute('value')));
                                $this->result[$groupName."/".$arrayGroupName] = $filters[$groupName.'/'.$arrayGroupName];
                            }
                        }
                        else
                        {
                            $this->result[$groupName."/".$reader->getAttribute('name')] = $this->castValue($reader->getAttribute('value'));
                        }
                        $reader->read();
                        $reader->read();
                    }
                }
                else if ($reader->name == 'glz:Param')
                {
                    if (strpos($reader->getAttribute('name'),'[]')  == true)
                    {
                        $arrayGroupName = substr($reader->getAttribute('name'), 0, -2);
                        if(empty($filters[$arrayGroupName]))
                        {
                            $filters[$arrayGroupName] = array();
                            array_push($filters[$arrayGroupName],$this->castValue($reader->getAttribute('value')));
                            $this->result[$$arrayGroupName] = $filters[$arrayGroupName];
                        }
                        else
                        {
                            array_push($filters[$arrayGroupName],$this->castValue($reader->getAttribute('value')));
                            $this->result[$arrayGroupName] = $filters[$arrayGroupName];
                        }
                    }
                    else
                    {
                        $this->result[$reader->getAttribute('name')] = $this->castValue($reader->getAttribute('value'));
                    }
                }
                else if ($reader->name == 'glz:Import')
                {
                    $file = $reader->getAttribute('src');
                    $newConfig = new Config($file);
                    $newConfig->parseFile();
                }
            }
            return $this->result;

        }

Как я могу объединять, каждый раз, результат, который я получаю при разборе файла, когда нахожу тег ?

Спасибовы так много!

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

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

В DOM это менее сложно:

function readConfigurationFile($fileName) {
  $document = new DOMDocument();
  $document->load($fileName);
  $xpath = new DOMXpath($document);
  $xpath->registerNamespace('g', 'http://www.glizy.org/dtd/1.0/');

  $result = [];
  foreach ($xpath->evaluate('/g:Config/*[self::g:Import or self::g:Group]') as $node) {
    switch ($node->localName) {
    case 'Import' :
      $result = array_merge($result, readConfigurationfile($node->getAttribute('src')));
      break;
    case 'Group' :
      $groupName = $node->getAttribute('name'); 
      foreach ($xpath->evaluate('g:Param', $node) as $paramNode) {
        $result[
          sprintf('%s/%s', $groupName, $paramNode->getAttribute('name'))
        ] = $paramNode->getAttribute('value');
      } 
      break;
    }
  }
  return $result;
}

var_dump(readConfigurationFile('main.xml'));

Вывод:

array(4) {
  ["folder/width"]=>
  string(3) "100"
  ["folder/height"]=>
  string(3) "200"
  ["thumbnail/width"]=>
  string(3) "200"
  ["thumbnail/height"]=>
  string(1) "*"
}

Подход такой же в XMLReader, но немного более сложный.

function readLargeConfigurationFile($fileName) {

  $reader = new XMLReader();
  $reader->open($fileName);

  $xmlns = 'http://www.glizy.org/dtd/1.0/';
  $document = new DOMDocument();
  $xpath = new DOMXpath($document);
  $xpath->registerNamespace('g', $xmlns);

  $result = [];

  // find the first Import or Group in the namespace
  do {
    $found = $reader->read();
  } while(
    $found && 
    !(
       $reader->namespaceURI === $xmlns && 
       ($reader->localName === 'Import' || $reader->localName === 'Group')
    )
  );

  while ($found) {
    switch ($reader->localName) {
    case 'Import' :
      $result = array_merge($result, readLargeConfigurationFile($reader->getAttribute('src')));
      break;
    case 'Group' :
      // expand Group into DOM for easier access
      $groupNode = $reader->expand($document);
      $groupName = $groupNode->getAttribute('name'); 
      foreach ($xpath->evaluate('g:Param', $groupNode) as $paramNode) {
        // read a Param
        $result[
          sprintf('%s/%s', $groupName, $paramNode->getAttribute('name'))
        ] = $paramNode->getAttribute('value');
      } 
      break;
    }

    // iterate sibling nodes to find the next Import or Group
    do {
      $found = $reader->next();
    } while(
      $found && 
      !(
        $reader->namespaceURI === $xmlns && 
        ($reader->localName === 'Import' || $reader->localName === 'Group')
      )
    ); 
  } 
  return $result;
}

var_dump(readLargeConfigurationFile('main.xml'));

Обратите внимание, что в примере не используется свойство $name.Он содержит псевдоним / префикс пространства имен glz.Префиксы пространства имен являются необязательными и могут изменяться даже в одном документе.Используйте свойства $localName и $namespaceURI.

С помощью XMLReader::expand() вы можете расширить текущий узел в DOM.Типичным подходом является итерация только внешних узлов с помощью XML-ридера.Если вы знаете, что узел и его потомки достаточно малы, вы расширяете их в DOM для более легкого доступа.

0 голосов
/ 12 июня 2018

Насколько я понимаю ваш вопрос, вам нужно немного реорганизовать ваш код.

Перепишите функцию парсера без ссылок на $ this-> result и $ this-> fileName.

Переопределите эти переменные в вашей функции как $ result и $ fileName.добавьте $ fileName в качестве аргумента функции.

Добавьте еще одну переменную $ result_config в функцию.

, когда вы читаете тег config, вызывайте функцию рекурсивно, вместо создания нового класса:

 -$file = $reader->getAttribute('src');
 - $newConfig = new Config();

 + $file = $reader->getAttribute('src');
 + $result_config = $this->parseFile($file);

Затем объедините два результата после того, как вы закончите с обоими файлами:

if ($result_config) {
    $this->result = array_merge($result_config, $this->result);
}
return $this->result;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...