I have the following XML:
<?xml version="1.0"?>
<STATUS_LIST>
<ORDER_STATUS SORDER_CODE="SO001" ASSOCIATED_REF="001">
<INVOICES>
<INVOICE INVOICE_CODE="???">SOMETHING</INVOICE>
</INVOICES>
</ORDER_STATUS>
</STATUS_LIST>
When I run the following code:
$statuses = simplexml_load_string($result); //Where $result is my XML
if (!empty($statuses))
{
foreach ($statuses as $status)
{
foreach ($status->INVOICES as $invoice)
{
echo (string)$invoice->attributes()->INVOICE_CODE;
}
}
}
I step through this code and I can see the attributes against ORDER_STATUS
but I can't see the attributes against INVOICE
. I can however see the value SOMETHING
against invoice.
Any idea what could cause this?
Update
After some testing, I can get the attributes to show if I add an element into the INVOICE
element, so if I use this xml instead it will work:
<?xml version="1.0"?>
<STATUS_LIST>
<ORDER_STATUS SORDER_CODE="SO001" ASSOCIATED_REF="001">
<INVOICES>
<INVOICE INVOICE_CODE="???"><TEST>tester</TEST></INVOICE>
</INVOICES>
</ORDER_STATUS>
</STATUS_LIST>
So it has to have an element inside to pick up the attributes!?
Your problem has nothing to do with the element having no content, you simply have your loops defined slightly wrong.
When you write foreach ($status->INVOICES as $invoice)
, SimpleXML will loop over every child of the $status
element which is called INVOICES
; in this case there will always be exactly one such element. But what you actually wanted is to loop over all the children of that element - the individual INVOICE
nodes.
To do that you can use one of the following:
foreach ($status->INVOICES->children() as $invoice)
(loop over all child nodes of the first, and in this case only, INVOICES
element)foreach ($status->INVOICES[0]->children() as $invoice)
(the same, but being more explicit about selecting the first INVOICES
node)foreach ($status->INVOICES[0] as $invoice)
(actually does the same again: because you've specifically selected one node, and then asked for a loop, SimpleXML assumes you want its children; this is why foreach($statuses as $status)
works as the outer loop)foreach ($status->INVOICES->INVOICE as $invoice)
(loop over only child nodes called INVOICE
, which happens to be all of them)Personally, I would rewrite your sample loop as below:
foreach ($statuses->ORDER_STATUS as $status)
{
foreach ($status->INVOICES->INVOICE as $invoice)
{
echo (string)$invoice['INVOICE_CODE'];
}
}