I have this XML file, and basically I want to be able to construct an array []key=>value
such as
[0]['Product Id']=>productId_1,
[0]['Product Name']=>product_name_1...
[1]['Product Id']=>productId_2,
[1]['Product Name']=>product_name_2
and so on. I've tried simplexml_load_file
, and struggled to reach the node (getName()
, attributes()
) with naught success. A print_r($obj)
shows a numbered array under FL, which I can reach, but I want the names ("Product ID") as well as the values. That I cannot do. I'm not at all familiar with XML, could anyone give a little help please? Couldn't find anything to match my problem in a 2 days search. Hope I explained myself properly.
<Invoices>
<row num="1">
<FL val="Product Details">
<product no="1">
<FL val="Product Id">productId_1</FL>
<FL val="Product Name">product_name_1</FL>
<FL val="Quantity">1</FL>
<FL val="List Price">1.00</FL>
<FL val="Discount">0</FL>
<FL val="Total">1.00</FL>
<FL val="Total After Discount">1.00</FL>
<FL val="Tax">0</FL>
<FL val="Net Total">1.00</FL>
</product>
</FL>
</row>
<row num="....">
</row>
</Invoices>
Let's take a look how this works in SimpleXML:
<FL val="Product Id">productId_1</FL>
^^^ ^^^
| |
"val" attribute |
<FL> element
Let's say this XML <FL>
-element would be stored in variable $FL
, you then can access the ...
val
" attribute value with $FL['val']
<FL>
element value with $FL
directly.To put that into an array, it is important to convert the values to strings. I use the trim
function for that, casting to string with (string)
would work, too:
$array = array();
$key = trim($FL['val']);
$value = trim($FL);
$array[$key] = $value;
Exemplary $array
then is:
Array
(
[Product Id] => productId_1
)
So now in the XML there are multiple <FL>
-elements within the <product>
-elements. Let's say that $product
would be the first product-element. The lines from above only need to be wrapped inside a foreach
loop over all <FL>
-elements:
$array = array();
foreach ($product->FL as $FL) {
$key = trim($FL['val']);
$value = trim($FL);
$array[$key] = $value;
}
Exemplary $array
then is:
Array
(
[Product Id] => productId_1
[Product Name] => product_name_1
[Quantity] => 1
[List Price] => 1.00
[Discount] => 0
[Total] => 1.00
[Total After Discount] => 1.00
[Tax] => 0
[Net Total] => 1.00
)
Now finally you only need to convert all products. Because it works for all products as it works for one product, you can put the logic into a function of it's own:
function product(SimpleXMLElement $product)
{
$array = array();
foreach ($product->FL as $FL) {
$key = trim($FL['val']);
$value = trim($FL);
$array[$key] = $value;
}
return $array;
}
Then you use an xpath query to obtain all product elements and do the mapping:
$xml = simplexml_load_string($buffer);
$result = array_map('product', $xml->xpath('//product'));
The output then is:
Array
(
[0] => Array
(
[Product Id] => productId_1
[Product Name] => product_name_1
[Quantity] => 1
[List Price] => 1.00
[Discount] => 0
[Total] => 1.00
[Total After Discount] => 1.00
[Tax] => 0
[Net Total] => 1.00
)
)
I hope this makes things a little more clear for you.
And here the example in full:
<?php
/**
* Make key=>value array from zoho XML file
* @link http://stackoverflow.com/a/29461013/367456
*/
$buffer = <<<XML
<Invoices>
<row num="1">
<FL val="Product Details">
<product no="1">
<FL val="Product Id">productId_1</FL>
<FL val="Product Name">product_name_1</FL>
<FL val="Quantity">1</FL>
<FL val="List Price">1.00</FL>
<FL val="Discount">0</FL>
<FL val="Total">1.00</FL>
<FL val="Total After Discount">1.00</FL>
<FL val="Tax">0</FL>
<FL val="Net Total">1.00</FL>
</product>
</FL>
</row>
<row num="....">
</row>
</Invoices>
XML;
function product(SimpleXMLElement $product)
{
$array = array();
foreach ($product->FL as $FL) {
$key = trim($FL['val']);
$value = trim($FL);
$array[$key] = $value;
}
return $array;
}
$xml = simplexml_load_string($buffer);
$result = array_map('product', $xml->xpath('//product'));
print_r($result);
Use a DOMDocument
combined with some DOMXPath
queries:
$source = <<<EOS
<Invoices>
<row num="1">
<FL val="Product Details">
<product no="1">
<FL val="Product Id">productId_1</FL>
<FL val="Product Name">product_name_1</FL>
<FL val="Quantity">1</FL>
<FL val="List Price">1.00</FL>
<FL val="Discount">0</FL>
<FL val="Total">1.00</FL>
<FL val="Total After Discount">1.00</FL>
<FL val="Tax">0</FL>
<FL val="Net Total">1.00</FL>
</product>
</FL>
</row>
<row num="2">
<FL val="Product Details">
<product no="2">
<FL val="Product Id">productId_2</FL>
<FL val="Product Name">product_name_2</FL>
<FL val="Quantity">2</FL>
<FL val="List Price">2.00</FL>
<FL val="Discount">0</FL>
<FL val="Total">2.00</FL>
<FL val="Total After Discount">2.00</FL>
<FL val="Tax">0</FL>
<FL val="Net Total">2.00</FL>
</product>
</FL>
</row>
</Invoices>
EOS;
$dom = new DOMDocument();
$dom->loadXML($source);
$xpath = new DOMXPath($dom);
$products = $xpath->query('//product');
foreach ($products as $product) {
$fls = $xpath->query('.//FL', $product);
$row = [];
foreach ($fls as $fl) {
$row[$fl->getAttribute('val')] = $fl->nodeValue;
}
$result[] = $row;
}
print_r($result);
Output:
Array
(
[0] => Array
(
[Product Id] => productId_1
[Product Name] => product_name_1
[Quantity] => 1
[List Price] => 1.00
[Discount] => 0
[Total] => 1.00
[Total After Discount] => 1.00
[Tax] => 0
[Net Total] => 1.00
)
[1] => Array
(
[Product Id] => productId_2
[Product Name] => product_name_2
[Quantity] => 2
[List Price] => 2.00
[Discount] => 0
[Total] => 2.00
[Total After Discount] => 2.00
[Tax] => 0
[Net Total] => 2.00
)
)