XML met namespaces uitlezen

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Nick Knoops

Nick Knoops

14/07/2020 16:43:34
Quote Anchor link
Hallo allemaal,

Ik loop tegen een probleem aan met het uitlezen van een xml bestand met de CBC namespace formattering.

Het XML bestand wordt als volgt ingeladen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
$xml_file
= 'INV-120024175_CUS-1000637-multiple_orders.XML';
$xmlfile = file_get_contents( $xml_file );
$ob = simplexml_load_string($xmlfile, 'SimpleXMLElement', LIBXML_NOCDATA);

Vervolgens loop ik door de xml met:
/Init the array    
$string_test = [];
foreach($ob->xpath('//cac:InvoiceLine') as $invoice) {
        
$string_ID = (string)$invoice->children('cbc', true)->ID.PHP_EOL;        
$string_test [$string_ID]['ID'] = (string)$invoice->children('cbc', true)->ID.PHP_EOL;        
$string_test [$string_ID]['Note'] = (string)$invoice->children('cbc', true)->Note.PHP_EOL;        
$string_test [$string_ID]['InvoicedQuantity'] = (string)$invoice->children('cbc', true)->InvoicedQuantity.PHP_EOL;    
    
$string_test [$string_ID]['LineExtensionAmount'] = (string)$invoice->children('cbc', true)->LineExtensionAmount.PHP_EOL; //Non working code to get the contents of the item node...        

$item = $invoice->xpath('//cac:Item');          
$array = json_decode(json_encode($item), TRUE);
#print_r($array);

//echo "<br>" . (string)$item->children('cbc', true)->Name.PHP_EOL;


}

//Print the full array foreach($string_test as $string){            
print_r($string);
}

?>


Voor de top level items werkt het perfect, maar zodra ik bijvoorbeeld binnenin cbc:item waardes wil uitlezen loop ik vast. Iemand die er ervaring mee heeft? Via deze link is een voorbeeld te zien van de XML file: https://stackoverflow.com/questions/39314888/how-to-parse-the-below-xml-file-in-php

Edit:
Ik heb code-tags geplaatst om het script. Gelieve dat in het vervolg zelf te doen.
Zie ook de opmaakcodes in de Veelgestelde Vragen.
Gewijzigd op 14/07/2020 16:54:50 door - Ariën -
 
PHP hulp

PHP hulp

15/08/2020 09:05:34
 
Thomas van den Heuvel

Thomas van den Heuvel

14/07/2020 23:06:49
Quote Anchor link
Misschien heb je hier iets aan:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
foreach ($invoice->xpath('//cac:Item') as $item) {
    $cbc = $item->xpath('descendant::cbc:*'); // array van SimpleXMLElement objecten van alle onderliggende elementen met een cbc namespace
    foreach ($cbc as $elt) {
        echo $elt->getName().': '.$elt.'<br>'; // voor $elt wordt de __toString() methode aangeroepen
    }
}

?>

Dit levert (met het XML document uit bovenstaande StackOverflow thread):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
Description: TITLE
ID: 9789079995318
Name: Afnemer
Value: ABC


Op een soortgelijke wijze zou je de selectie van de Invoice elementen (ID, InvoicedQuantity) ook kunnen selecteren met de "XML axis" child::.
 
Nick Knoops

Nick Knoops

15/07/2020 09:12:27
Quote Anchor link
Hallo Thomas,

Bedankt! Ik ga het morgen gelijk testen. Ik dacht al dat het iets met de notatie te maken, maar dat er "descendents::" gebruikt moest worden was ik zelf zo niet opgekomen.
 
Thomas van den Heuvel

Thomas van den Heuvel

15/07/2020 16:28:53
Quote Anchor link
Ik ook niet, heb hier best lang op zitten zoeken, maar xpath is een ontzettend krachtige "querytaal" voor XML-structuren (waar ik verder nauwelijks iets van weet :p). Het is "gewoon" een kwestie van de juiste vraag (aan XML) formuleren, en dan uitzoeken hoe je dat opschrijft in het xpath-dialect.
 
Nick Knoops

Nick Knoops

16/07/2020 10:23:44
Quote Anchor link
Hey Thomas,

Het is me bijna gelukt! Ik zit nog met één kleine issue en dan heb ik het opgelost. Ik heb me suf gezocht op de juiste selector(s). Ik snap nu je woorden dat het lastig te vinden is :P

In mijn originele foreach, waarin ik door alle invoicelines loop, heb ik een nieuwe foreach gemaakt met het doel om van de invoiceline in kwestie de "item" eruit te halen en deze waardes toe te voegen aan de originele array. Hiervoor heb ik je code gebruikt met 'descendant::cbc:*' om deze op te halen. Volgens heb ik deze in een nieuwe array gestopt met de naam van de node als de Key en de waarde als value. Deze array voeg ik dan weer toe aan de originele onder de key "item". Alleen komt er dan overal alleen 't laatste item uit de laatste invoiceline bij te staan.

Ik zie even niet wat ik fout doe, heb jij een idee?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
  //Init the array
    $invoiceLineArray = [];
    $itemArray = [];

    foreach($ob->xpath('//cac:InvoiceLine') as $invoice)
    {

        $invoiceLineID = (string)$invoice->children('cbc', true)->ID.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['ID'] = (string)$invoice->children('cbc', true)->ID.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['Note'] = (string)$invoice->children('cbc', true)->Note.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['InvoicedQuantity'] = (string)$invoice->children('cbc', true)->InvoicedQuantity.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['LineExtensionAmount'] = (string)$invoice->children('cbc', true)->LineExtensionAmount.PHP_EOL;

        foreach ($invoice->xpath('//cac:Item') as $item) {
            $children = $item->xpath('descendant::cbc:*'); // array van SimpleXMLElement objecten van alle onderliggende elementen met een cbc namespace
            
            //print_r($children); // -> deze print alle items uit elke invoiceline uit


            foreach ($children as $child) {

               // print_r($child);

                $name = $child->getName();

                $itemArray[$name] = $child.PHP_EOL;

              // print_r($itemArray);

             }
            $invoiceLineArray [$invoiceLineID]['Item'] = $itemArray; // -> Maak een nieuwe key aan en vul deze met de items uit "Item"
        }
      
    }


    //print_r( $itemArray, false );

    print_r($invoiceLineArray, false); // -> print alleen het item uit de laatste invoiceline
?>


Toevoeging op 16/07/2020 11:10:48:

Een update, ben inmiddels wel its dichterbij gekomen.

Via deze test:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
    $abc
= 3;
    $invoicelinetest = $ob->xpath('//cac:InvoiceLine['.$abc.']/cbc:ID');
    echo $invoicelinetest[0];
?>


Ben ik er achter gekomen dat ik op deze manier de ID van invoiceline nummer 3 kan pakken.

Nu bracht me dit op het volgende idee, een $count variabelen toevoegen aan de foreach, zodat ik weet om welke invoiceline het gaat. Vervolgens wil ik deze uitlezen met:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

 foreach($ob->xpath('//cac:InvoiceLine') as $invoice)
    {

        $count += 1;
        $invoiceLineID = (string)$invoice->children('cbc', true)->ID.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['ID'] = (string)$invoice->children('cbc', true)->ID.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['Note'] = (string)$invoice->children('cbc', true)->Note.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['InvoicedQuantity'] = (string)$invoice->children('cbc', true)->InvoicedQuantity.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['LineExtensionAmount'] = (string)$invoice->children('cbc', true)->LineExtensionAmount.PHP_EOL;
      
        foreach ($invoice->xpath('//['.$count.']/cac:Item') as $item) {

?>


Ik zit nog even te stoeien met hoe ik het nummer van de invoiceLine (de count variabelen) in een goede xpath variabelen kan krijgen..
Gewijzigd op 16/07/2020 10:31:55 door Nick Knoops
 
Thomas van den Heuvel

Thomas van den Heuvel

16/07/2020 17:03:58
Quote Anchor link
Heb je gecontroleerd of ID niet toevallig hetzelfde is voor alle InvoiceLines? Dat zou verklaren waarom je array maar één entry heeft (dezelfde index wordt telkens overschreven).

De betekenis is mij niet direct duidelijk, maar als je een unieke index nodig hebt is OrderLineReference.LineID misschien een betere kandidaat, of zijn dit nummers uit verschillende systemen?
Gewijzigd op 16/07/2020 19:47:15 door Thomas van den Heuvel
 
Nick Knoops

Nick Knoops

22/07/2020 16:58:35
Quote Anchor link
Wat late reactie, maar ik heb het wel werkend gekregen gelukkig :D

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
//Initialize the arrays
    $invoiceLineArray = [];
    $itemArray = [];
    $sellersItemIDArray = [];
    $priceArray = [];

    $count = 0;

    foreach($ob->xpath('//cac:InvoiceLine') as $invoice)
    {

        $count += 1;
        $invoiceLineID = (string)$invoice->children('cbc', true)->ID.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['ID']                    = (string)$invoice->children('cbc', true)->ID.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['Note']                  = (string)$invoice->children('cbc', true)->Note.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['InvoicedQuantity']      = (string)$invoice->children('cbc', true)->InvoicedQuantity.PHP_EOL;
        $invoiceLineArray [$invoiceLineID]['LineExtensionAmount']   = (string)$invoice->children('cbc', true)->LineExtensionAmount.PHP_EOL;
        
        //Fill the array with the descendants of the cac:Item node
        foreach ($invoice->xpath('//cac:InvoiceLine['. $count .']/cac:Item') as $item) {
            $children = $item->xpath('descendant::cbc:*'); // array van SimpleXMLElement objecten van alle onderliggende elementen met een cbc namespace
            
            foreach ($children as $child) {
                $name = $child->getName();
                $itemArray[$name]  = $child.PHP_EOL;
             }
            
        }


        //Fill the array with the descendants of the cac:SellersItemIdentification node
        foreach ($invoice->xpath('//cac:InvoiceLine['. $count .']/cac:Item/cac:SellersItemIdentification') as $item) {
            $children = $item->xpath('descendant::cbc:*'); // array van SimpleXMLElement objecten van alle onderliggende elementen met een cbc namespace
            foreach ($children as $child) {
                $name               = $child->getName();
                $sellersItemIDArray[$name]   = $child.PHP_EOL;
             }
        }


        //Fill the array with the descendants of the cac:Price node
        foreach ($invoice->xpath('//cac:InvoiceLine['. $count .']/cac:Price') as $item) {
            $children = $item->xpath('descendant::cbc:*'); // array van SimpleXMLElement objecten van alle onderliggende elementen met een cbc namespace
            foreach ($children as $child) {
                $name               = $child->getName();
                $priceArray[$name]  = $child.PHP_EOL;
             }
        }


        $invoiceLineArray [$invoiceLineID]['Item']  = $itemArray; //Fill the items
        $invoiceLineArray [$invoiceLineID]['SellersItemIdentification']  = $sellersItemIDArray; //Fill the items
        $invoiceLineArray [$invoiceLineID]['Price'] = $priceArray; //Fill the items

    }

?>
Gewijzigd op 22/07/2020 16:59:06 door Nick Knoops
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.