XML met namespaces uitlezen
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)
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
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);
}
?>
$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.
Zie ook de opmaakcodes in de Veelgestelde Vragen.
Gewijzigd op 14/07/2020 16:54:50 door - Ariën -
Code (php)
1
2
3
4
5
6
7
8
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
}
}
?>
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):
Op een soortgelijke wijze zou je de selectie van de Invoice elementen (ID, InvoicedQuantity) ook kunnen selecteren met de "XML axis" child::.
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.
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.
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)
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
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
?>
//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)
1
2
3
4
5
2
3
4
5
<?php
$abc = 3;
$invoicelinetest = $ob->xpath('//cac:InvoiceLine['.$abc.']/cbc:ID');
echo $invoicelinetest[0];
?>
$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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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) {
?>
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
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
Code (php)
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
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
}
?>
//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