I'm using XML to insert products into my db with PHP. I can access / read the xml feed with the following code:
$xml=simplexml_load_file('testfeed.xml') or die("Error: Cannot create object");
foreach($xml->children() as $product) {
$pname = $product->name;
$pdescr = $product->description;
echo $pname;
echo $pdescr;
}
Below is my example XML:
<product ID="9">
<name>Product X</name>
<properties>
<property name="categoryPath">
<value>path-to-category</value>
</property>
<property name="stock">
<value>1</value>
</property>
</properties>
</product>
It's easy to get the values for name, but how do I get the value of the categorypath, since this one is inside properties->property->value and declared in the <property name="categoryPath">?
Thanks!
The easiest way without looping too much through the structures will be using XPath:
$values = $xml->xpath('//property[#name="categoryPath"]/value');
Just loop through the returned array and cast each result to string when needed, and you're done.
$xml=simplexml_load_file('./testfeed.xml') or die("Error: Cannot create object");
foreach($xml->children() as $product) {
$pname = $product->name;
$pdescr = $product->properties->property["name"];
$pdvalue = (string)$product->properties->property->value;
echo "Prdo Name: $pname\n";
echo "Prod Desc: $pdescr\n";
echo "Prod Value: $pdvalue\n";
}
Output:
Prdo Name: Product X
Prod Desc: categoryPath
Prod Value: path-to-category
Update:
While Jossif's answer is very good at getting all the nodes in bulk I'm including an edit for updated xml structure without using xpath:
$property = $product->properties->property;
$propertyAttribute = $property->attributes()->{'name'};
$catPath = ($propertyAttribute=="categoryPath")? $property->value : "value for missing paths";
print $catPath . PHP_EOL;
Since you don't seem to have any other similar xml nodes, you don't need the attribute to separate them.
You should be able to safely use this
$catPath = $product->properties->property->value;
print $catPath;
to get the string from the value node.
Related
I have an XML structure like this
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
<county>
</location>
</company>
</companies>
I am trying to get specific info from the elements into PHP variables.
To get "vatno" I use:
$vatno = $xmlObject->item($i)->getElementsByTagName('vatno')->item(0)->childNodes->item(0)->nodeValue;
But what if I need the county name for example?
I cannot use getElementsByTagName('text') as it would get the company name also using the element name "text".
You may be better off using SimpleXML, you can then access the various components in a more intuitive way.
The example above would be something like...
$data = <<< XML
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
</county>
</location>
</company>
</companies>
XML;
$xml = simplexml_load_string($data);
foreach ( $xml->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
So each sub element is accessed using ->.
If you wanted to stick with what you already had, you should be able to use...
$countyName = $xmlObject->item($i)->getElementsByTagName('text')->item(1)
->nodeValue;
Using item(1) will fetch the second instance of the <text> elements, so this assumes that the name will have this value as well.
It works with SimpleXML if I use
$xml = simplexml_load_string($data);
foreach ( $xml->companies->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
I'm trying to read an XML file with PHP but I'm only getting the first result and can't figure out why.
XML structure:
<main>
<data>
<record>
<column name="title">Some title here</column>
</record>
<record>
<column name="title">Some second title here</column>
</record>
</data>
</main>
Pretty basic. This is the code I'm using to getting the results:
foreach($XML->data->record as $product) {
$title = mysql_real_escape_string($product->title);
}
But this only gives an empty string so I guess I'm looking at the wrong path. The code below does work, but only gives me the first record and not the other records in the XML file.
foreach($XML->data as $product) {
$title = mysql_real_escape_string($product->record->title);
}
The answer is probably easy, but I can't figure it out. Hope someone is willing to help :)
title is the value of the name attribute of the <column> node.
You can't access it the way you do it.
To access the <column> node:
$xml = simplexml_load_string($x); // assume XML in $x
foreach ($xml->data->record as $product) {
echo $product->column;
}
Output:
Some title here
Some second title here
see it working: https://eval.in/506519
If there are many columns under each record...
<record>
<column name="title">Some title here</column>
<column name="car">BMW</column>
<column name="color">red</column>
</record>
... and you want to list all, you need a second loop:
foreach ($xml->data->record as $product) { // same as above
foreach ($product->column as $column) { // iterate all column
echo $column['name'] . ": " . $column . PHP_EOL;
}
}
Output:
title: Some title here
car: BMW
color: red
see it working: https://eval.in/506521
In case you want only <column> nodes with name = "title", check with if:
foreach ($xml->data->record as $product) { // same as above
foreach ($product->column as $column) { // iterate all column
if ($column['name'] == "title") echo $column . PHP_EOL;
}
}
see it working: https://eval.in/506523
And be aware that there is a different way to get all <column> with name = "title" with xpath:
$titles = $xml->xpath("//column[#name = 'title']");
foreach ($titles as $title)
echo $title . PHP_EOL;
see it in action: https://eval.in/506531
For an explanation of the xpath syntax, look at Using xPath to access values of simpleXML and zillion others.
and BTW: as said in comments, don't use mysql_...
Not tested but looks ok. Load the xml file / string into DOMDocument and get all the column nodes and iterate through them
$dom=new DOMDocument;
$dom->loadXML( $strxml );
/*
or
--
$dom->load( $xmlfile );
*/
$col=$dom->getElementsByTagName('column');
foreach( $col as $node ){
echo $node->tagName.' '.$node->getAttribute('title').' '.$node->nodeValue;
}
I have the following xml doc:
<shop id="123" name="xxx">
<product id="123456">
<name>Book</name>
<price>9.99</price
</product>
<product id="789012">
<name>Perfume</name>
<price>12.99</price
</product>
<product id="345678">
<name>T-Shirt</name>
<price>9.99</price
</product>
</shop>
<shop id="456" name="yyy">
<product id="123456">
<name>Book</name>
<price>9.99</price
</product>
</shop>
I have the following loop to gather the information for each product:
$data_feed = 'www.mydomain.com/xml/compression/gzip/';
$xml = simplexml_load_file("compress.zlib://$data_feed");
foreach ($xml->xpath('//product') as $row) {
$id = $row["id"]; // product id eg. "123456"
$name = $row->name;
$price = $row->price;
// update database etc.
}
HOWEVER, I also want to gather the information for each product's parent shop ("id" and "name").
I can easily change my xpath to start from shop as opposed to product, but I'm unsure of the most efficient way to then construct an additional loop within my foreach to loop each indented product
Make sense?
I'd go without xpath and just use two nested foreach-loops:
$xml = simplexml_load_string($x); // assume XML in $x
foreach ($xml->shop as $shop) {
echo "shop $shop[name], id $shop[id] <br />";
foreach ($shop->product as $product) {
echo "- $product->name (id $product[id]), $product->price <br />";
}
}
see it working: http://codepad.viper-7.com/vFmGvY
BTW: your XML is broken, probably a typo. Each closing </price> is missing its last >.
Sure, makes sense, you want one iteration, not a nested product of iterations (albeit that won't cut you much, #michi showed already), which is possible as well:
foreach ($xml->xpath('//product') as $row)
{
$id = $row["id"]; // product id eg. "123456"
$name = $row->name;
$price = $row->price;
$shopId = $row->xpath('../#id')[0];
$shopName = $row->xpath('../#name')[0];
// update database etc.
}
As this example shows, you can run xpath() on each element-node and the context-node is automatically set to the node itself, therefore the realtive path .. in xpath works to access the parent element (see as well: Access an element's parent with PHP's SimpleXML?). Of that then both attributes are read and then via PHP 5.4 array de-referencing the first (and only) attribute is accessed.
I hope this helps and shed some light how it works. Your question reminds me a bit of an earlier one where I suggested some kind of generic solution to these kind of problems:
Answer to Combining two Xpaths into one loop?
I am having trouble getting all the data from my XML. Can any one shed some light please.
My XML is as follows
<storeitems>
<PRODUCT ITEM="3002074730">
<SPECIALS_ID>14713</SPECIALS_ID>
<FULL_PRICE>27.00</FULL_PRICE>
<SPECIALS_NEW_PRODUCTS_PRICE>25.65</SPECIALS_NEW_PRODUCTS_PRICE>
</PRODUCT>
<PRODUCT ITEM="SE-0088-10-3">
<SPECIALS_ID>29555</SPECIALS_ID>
<FULL_PRICE>53.99</FULL_PRICE>
<SPECIALS_NEW_PRODUCTS_PRICE>51.29</SPECIALS_NEW_PRODUCTS_PRICE>
</PRODUCT>
<storeitems>
My code is as follows
$xml = new SimpleXMLElement($data);
foreach($xml->PRODUCT as $post) {
echo $post->SPECIALS_ID .'<BR>';
echo $post->FULL_PRICE . '<BR>';
echo $post->SPECIALS_NEW_PRODUCTS_PRICE . '<BR>';
}
This does what I expect but can you assist me in getting this part of the XML to echo please
<PRODUCT ITEM="3002074730">
echo $post->attributes();
will print the value of your item (first) attribute (it's an object that does that when it's called in a string-context).
If you add more attributes and you want to get them all, you can iterate over $post->attributes():
foreach($post->attributes() as $name => $value){
...
}
I work with many different types of xml files. I load the contents of these into my mysql database. Problem is that i need to define the tags I want to pick everytime.
Is there a php dom object functions that can iterate over all the tags and give them to me.
this is my sample xml
<products>
<product>
<name>Name of product</name>
<categories>
<category>Apparel</category>
<category>Trousers</category>
<category>Blue</category>
</categories>
<description>Blue trousers</description>
<price>599.00</price> <regularPrice>599.00</regularPrice>
</product>
</products>
Output should be NOT the values but the acctual name of the XML tags, in this case it should be
Products, Product, Name, Categories, category, description, price
Getting those values I could dynamicly point them via a connection table to always be save in the right table and in the right field.
*Try this code it will work as expected *
$xmlD = '
<products>
<product>
<name>Name of product</name>
<categories>
<category>Apparel</category>
<category>Trousers</category>
<category>Blue</category>
</categories>
<description>Blue trousers</description>
<price>599.00</price> <regularPrice>599.00</regularPrice>
</product>
</products>
';
$xml = simplexml_load_string($xmlD);
echo $xml->getName() . "<br />";
foreach($xml->children() as $child)
{
echo $child->getName(). "<br />";
foreach($child->children() as $innerChild):
echo $innerChild->getName(). "<br />";
endforeach;
}