PHP XPath. Конвертировать сложный XML в массив

После трех дней попыток решить это самостоятельно я должен сдаться. Это выдержка из огромного XML-файла, экспортированного из дБ итальянских законов. Я хотел бы преобразовать этот XML в массив PHP, так как цель состоит в том, чтобы использовать этот массив для построения отформатированного документа Word с использованием класса PHP как PHP2RTF.

<CodiceRegionale>
    <sommario>
        <elementoCapitolo>CAP a1</elementoCapitolo>
        <elementoCapitoloDescr>
        </elementoCapitoloDescr>
        <elementoSommarioLegge>
             <elementoTesto>1.1 Legge</elementoTesto>
        </elementoSommarioLegge>
    </sommario>
    <LeggeRegionale id="urn:nir:2014-12-12;26" xmlns="http://www.normeinrete.it/nir/2.1/">
         <elementoSommario xmlns="">
             <elementoCapitolo>CAP a1</elementoCapitolo>
             <elementoCapitoloDescr>
             </elementoCapitoloDescr>
             <elementoSettore />
             <elementoSettoreDescr />
         </elementoSommario>
         <intestazione>Lex 12 2014, n. 26.</intestazione>
             <articolato>
                 <articolo id="art41" xmlns="http://www.normeinrete.it/nir/2.1/">
                     <num>Art. 41</num>
                     <rubrica>(Riforma della finanza locale)</rubrica>
                     <comma id="art41-com1">
                          <num>1. </num>
                          <alinea>Al fine di supportare...</alinea>
                          <el id="art41-com1-let_a">
                              <num>a) </num>
                              <corpo>definizione di...</corpo>
                          </el>
                          <el id="art41-com1-let_b">
                               <num>b) </num>
                               <corpo>coordinamento della...</corpo>
                           </el>
                           <el id="art41-com1-let_c">
                               <num>c) </num>
                               <corpo>definizione delle...</corpo>
                           </el>
                           <el id="art41-com1-let_d">
                               <num>d) </num>
                               <corpo>la disciplina...</corpo>
                           </el>
                      </comma>
                      <comma id="art41-com2">
                           <num>2. </num>
                           <alinea>La revisione di...</alinea>
                           <el id="art41-com2-let_a">
                               <num>a) </num>
                               <corpo>
                                    razionalizzazione e...
                                    <rif xlink:href="urn:nir:stato:legge:2010-12-13;220#art1-com154" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink">articolo 1, comma 154, della legge 13 dicembre 2010, n. 220</rif>
                                    (Legge di stabilità 2011);
                               </corpo>
                           </el>
                           <el id="art41-com2-let_b">
                               <num>b) </num>
                               <corpo>
                                    applicazione dei...
                                    <rif xlink:href="urn:nir:stato:costituzione:1947-12-27#art119" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink">articolo 119 della Costituzione</rif>
                                    , nonché del principio...
                               </corpo>
                           </el>
                           <el id="art41-com2-let_c">
                               <num>c) </num>
                               <corpo>valorizzazione...</corpo>
                           </el>
                           <el id="art41-com2-let_d">
                               <num>d) </num>
                               <corpo>previsione di...</corpo>
                           </el>
                           <el id="art41-com2-let_e">
                               <num>e) </num>
                               <corpo>valorizzazione del...</corpo>
                           </el>
                           <el id="art41-com2-let_f">
                               <num>f) </num>
                               <corpo>previsione di...</corpo>
                           </el>
                       </comma>
                       <comma id="art41-com3">
                           <num>3. </num>
                           <corpo>La revisione normativa...</corpo>
                       </comma>
                       <comma id="art41-com4">
                           <num>4. </num>
                           <corpo>I disegni di...</corpo>
                       </comma>
                  </articolo>
                  <articolo id="art42" xmlns="http://www.normeinrete.it/nir/2.1/">
                      <num>Art. 42</num>
                      <rubrica>(Supporto finanziario regionale agli enti locali)</rubrica>
                      <comma id="art42-com1">
                          <num>1. </num>
                          <corpo>Il supporto...</corpo>
                      </comma>
                      <comma id="art42-com2">
                          <num>2. </num>
                          <corpo>Per le finalità di...</corpo>
                      </comma>
                      <comma id="art42-com3">
                          <num>3. </num>
                          <corpo>Gli incentivi regionali...</corpo>
                      </comma>
                      <comma id="art42-com4">
                          <num>4. </num>
                          <corpo>
                                In attuazione...
                                <rif xlink:href="urn:nir:stato:decreto.legislativo:1997-01-02;9#art9" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink">articolo 9 ...</rif>
                                (Norme di attuazione dello
                                <rif xlink:href="urn:nir:regione.friuli.venezia.giulia:statuto:" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink">statuto</rif>
                                speciale...
                          </corpo>
                      </comma>
                      <comma id="art42-com5">
                          <num>5. </num>
                          <corpo>Le modalità...</corpo>
                      </comma>
                  </articolo>
             </articolato>
        </LeggeRegionale>
        <LeggeRegionale id="urn:nir:2015-05-22;12" xmlns="http://www.normeinrete.it/nir/2.1/">
            <elementoSommario xmlns="">
                <elementoCapitolo>CAP a7</elementoCapitolo>
                <elementoCapitoloDescr>
                </elementoCapitoloDescr>
                <elementoSettore />
                <elementoSettoreDescr />
            </elementoSommario>
            <intestazione>Lex 22 2015 n. 12...</intestazione>
            <articolato>
                <articolo id="art6">
                    <num>Art. 6</num>
                    <rubrica>(Regolamento interno del CAL)</rubrica>
                    <comma id="art6-com1">
                        <num>1. </num>
                        <corpo>Il CAL approva...</corpo>
                    </comma>
                    <comma id="art6-com2">
                        <num>2. </num>
                        <alinea>Il regolamento...</alinea>
                        <el id="art6-com2-let_a">
                            <num>a) </num>
                            <corpo>l'elezione...</corpo>
                        </el>
                        <el id="art6-com2-let_b">
                            <num>b) </num>
                            <corpo>le funzioni degli organi del CAL;</corpo>
                        </el>
                        <el id="art6-com2-let_c">
                            <num>c) </num>
                            <corpo>la costituzione...</corpo>
                        </el>
                        <el id="art6-com2-let_d">
                            <num>d) </num>
                            <corpo>la programmazione...</corpo>
                        </el>
                        <el id="art6-com2-let_e">
                            <num>e) </num>
                            <corpo>i casi nei...</corpo>
                        </el>
                        <el id="art6-com2-let_f">
                            <num>f) </num>
                            <corpo>le modalità di...</corpo>
                        </el>
                    </comma>
                    <comma id="art6-com3">
                        <num>3. </num>
                        <corpo>Il regolamento è pubblicato...</corpo>
                    </comma>
               </articolo>
          </articolato>
     </LeggeRegionale>
     <LeggeRegionale id="urn:nir:2014-12-12;26" xmlns="http://www.normeinrete.it/nir/2.1/">
         <elementoSommario xmlns="">
             <elementoCapitolo>CAP a8</elementoCapitolo>
             <elementoCapitoloDescr>
             </elementoCapitoloDescr>
             <elementoSettore />
             <elementoSettoreDescr />
         </elementoSommario>
         <intestazione>Lex 12 2014, n. 26....</intestazione>
         <articolato>
             <articolo id="art17">
                  <num>Art. 17</num>
                  <rubrica>(Piano dell'Unione)</rubrica>
                  <comma id="art17-com1">
                      <num>1. </num>
                      <corpo>Il Piano dell'Unione...</corpo>
                  </comma>
                  <comma id="art17-com2">
                      <num>2. </num>
                      <corpo>
                                            Il Piano ...
                                            <rif xlink:href="urn:nir:stato:decreto.legislativo:2000;267#art170" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink">articolo 170 ...</rif>
                                            .
                      </corpo>
                 </comma>
                 <comma id="art17-com3">
                     <num>3. </num>
                     <corpo>Il Piano dell'Unione...</corpo>
                 </comma>
                 <comma id="art17-com4">
                     <num>4. </num>
                     <corpo>La relazione annuale...</corpo>
                 </comma>
            </articolo>
        </articolato>
   </LeggeRegionale>
   <LeggeRegionale id="urn:nir:regione.friuli.venezia.giulia:legge:2014-12-12;26" xmlns="http://www.normeinrete.it/nir/2.1/">
       <elementoSommario xmlns="">
           <elementoCapitolo>CAP a14</elementoCapitolo>
           <elementoCapitoloDescr>
           </elementoCapitoloDescr>
           <elementoSettore />
           <elementoSettoreDescr />
       </elementoSommario>
       <intestazione>Lex 12 dicembre 2014, n. 26 ....</intestazione>
       <articolato>
           <articolo id="art5">
               <num>Art. 5</num>
               <rubrica>(Unioni territoriali intercomunali)</rubrica>
               <comma id="art5-com1">
                   <num>1. </num>
                   <corpo>Le Unioni territoriali...</corpo>
               </comma>
               <comma id="art5-com2">
                   <num>2. </num>
                   <corpo>
                                L'Unione ha...
                                <rif xlink:href="urn:nir:stato:decreto.legislativo:2000-08-18;267#art32" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink">articolo 32...</rif>
                                (Testo unico delle leggi sull'ordinamento degli enti locali).
                   </corpo>
              </comma>
         </articolo>
    </articolato>
</LeggeRegionale>

Массив, который я пытаюсь построить, должен быть похож на следующее:

Array
(
    [LeggeRegionale] => Array
        (
            [intestazione] => Lex 12 2014, n. 26.
            [articolato] => Array
                (
                    [num] => Art. 41
                    [articolo] => Array
                        (
                            [rubrica] => (Riforma della finanza locale)
                            [commi] => Array
                                (
                                    [num_alinea] => 1. Al fine di supportare...
                                    [el] => Array
                                        (
                                            [num_corpo] => a) definizione di...
                                            [num_corpo] => b) coordinamento della...
                                        )
                                    [num_alinea] => 2. La revisione di...
                                 )
                          )
                     [num] => Art. 42
                     ...
                  )
           )
   )

С помощью этого кода я могу читать ВСЕ XML, но он абсолютно бесполезен:

$results = array();
$query = '//a:LeggeRegionale';
$result = $xpath->query($query);

$results = array();

for($i=0; $i < $result->length; $i++) {
    $results[$i] = $result->item($i)->nodeValue;
    echo $results[$i]."<BR><BR>";
}
echo "<BR>";

Этот код возвращает что-то структурированное (хотя это не массив, который я ищу), но я не понимаю, почему он возвращает только последнее вхождение LeggeRegionale когда я использовал foreach loop,

foreach ($result as $entry) {

    $result = [
        'intestazione' => $xpath->query('//a:LeggeRegionale')->item($i)->nodeValue,
        'articoli' => array(
                        'numero'    => $xpath->query('//a:articolato/a:articolo/a:num')->item($i)->nodeValue,
                        'rubrica'   => $xpath->query('//a:articolato/a:articolo/a:rubrica')->item($i)->nodeValue,
                        'commi' => array(
                                    'numero'    => $xpath->query('//a:articolato/a:articolo/a:comma/a:num')->item($i)->nodeValue,
                                    'corpo'     => $xpath->query('//a:articolato/a:articolo/a:comma/a:corpo|//a:articolato/a:articolo/a:comma/a:alinea')->item($i)->nodeValue,
                                    'lettere'   => array(
                                                    'lettera'   => $xpath->query('//a:articolato/a:articolo/a:comma/a:el')->item($i)->nodeValue,
                                    ),
                        ),
        ),
    ];
    array_push($a, $result);
    $i++;
}

Я думаю, что есть лучший способ - благодаря XPath - читать всех потомков, а не писать foreach loop для каждого уровня XML.

1 ответ

Решение

Преобразование сложного XML в массив приведет к... сложному массиву. Вам трудно читать XML, и вы думаете, что массивы намного проще для вас, поэтому массив должен быть решением. Но на самом деле XML хорошо подходит для анализа дерева в PHP. Массив не так доступен. Например, вы не можете запустить запрос xpath для массива.

А для массива в вашем псевдомассиве есть ошибка, что у вас есть дубликаты ключей. Структура больше похожа на:

Array
(
    [LeggeRegionale] => Array
        (
            [0] => Array
                (
                    [intestazione] => Lex 12 2014, n. 26.
                    [articolato] => Array
                        (
                            [articolo] => Array
                                (
                                    [0] => Array
                                        (
                                            [num] => Art. 41
                                            [rubrica] => (Riforma della finanza locale)
                                            [commi] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [num_alinea] => 1. Al fine di supportare...
                                                            [num_corpo] => Array
                                                                (
                                                                    [0] => a) definizione di...
                                                                    [1] => b) coordinamento della...
                                                                    [2] => c) definizione delle...
                                                                    [3] => d) la disciplina...
                                                                )

                                                        )

                                                    [1] => Array
                                                        (
                                                            [num_alinea] => 2. La revisione di...
                                                            [num_corpo] => Array
                                                                (
                                                                    [0] => a) razionalizzazione e... articolo 1, comma 154, della legge 13 dicembre 2010, n. 220 (Legge di stabilità 2011);
                                                                    [1] => b) applicazione dei... articolo 119 della Costituzione , nonché del principio...
                                                                    [2] => c) valorizzazione...
                                                                    [3] => d) previsione di...
                                                                    [4] => e) valorizzazione del...
                                                                    [5] => f) previsione di...
                                                                )

...

И это уже с некоторой оптимизацией (вы можете игнорировать неправильные символы в кодировке, это ошибка копирования и вставки).

Возможно, вы захотите использовать библиотеку, которая упрощает запрос дочерних узлов напрямую через xpath. Я дал ответ, который показывает небольшой и быстрый пример использования DOMXPath и функции запроса php, вам нужно добавить поддержку пространства имен для этого. Затем вам нужно будет позаботиться о построении массива, которое на самом деле довольно сложно:

$doc = new DOMDocument();
$doc->load('example.xml');

/* DOMBLAZE II XMLNS */ $doc->registerNodeClass("DOMElement", "DOMBLAZE"); # ...

/** @var $root DOMBLAZE */
$root = $doc->documentElement;
$root()->registerNamespace('a', 'http://www.normeinrete.it/nir/2.1/');

$array = [];
foreach ($root('a:LeggeRegionale') as $leggioRegionale) {
    $entry                 = [];
    $entry['intestazione'] = $leggioRegionale('string(./a:intestazione)');
    $articolato            = [];
    foreach ($leggioRegionale('a:articolato/a:articolo') as $articolo) {
    }
    $array[] = $entry;
}

print_r($array);

Этот пример (очевидно) неполный.

В качестве альтернативы я экспериментировал с записью выражений xpath в самом XML, который определяет "массив". Затем это можно было бы использовать с адаптированным SimpleXMLElement для рекурсивного построения массива на основе определения:

$doc = new DOMDocument();
$doc->load('example.xml');

$buffer = <<<XML
<xmlarray>
    <xml>
        <namespace prefix="a" uri="http://www.normeinrete.it/nir/2.1/"/>
    </xml>
    <array>
        <LeggeRegionale expr="a:LeggeRegionale">
            <intestazione expr="string(a:intestazione)"/>
            <articolato expr="a:articolato">
                <articolo expr="a:articolo">
                    <num expr="string(a:num)"/>
                    <rubrica expr="string(a:rubrica)"/>
                    <commi expr="a:comma">
                        <num_alinea expr="concat(a:num, a:alinea)"/>
                        <el expr="a:el" alias="num_corpo">
                            <num_corpo expr="normalize-space(concat(a:num, a:corpo))" cast="string"/>
                        </el>
                    </commi>
                </articolo>
            </articolato>
        </LeggeRegionale>
    </array>
</xmlarray>
XML;

$xmlArray = new XmlArrayElement($buffer);
$xmlArray->assignDocument($doc);
print_r($xmlArray->toArray());

Это действительно создает массив, представленный в начале ответа.

Конечно, теперь это выглядит как супер-решение для вас, но все, что он сделал, это обернул дерево XML в другое дерево, на этот раз в массив. Элемент XmlArrayElement не является частью примера в ответе, но представляет собой суть.

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

Также стоит рассмотреть в вашем случае XSLT, который технически был сделан для этого. Вы можете напрямую конвертировать в HTML-документ. Документы HTML гораздо более переносимы, чем документы RTF, и существуют инструменты для их преобразования в RTF, а также другие документы.

Другие вопросы по тегам