i have the following xml:
<?xml version="1.0" standalone="yes"?>
<Products>
<Product>
<name>Milk</name>
<price>1.4</price>
<productinfos>
<category1 value="somecategory1"/>
<category2 value="somecategory2"/>
<category3 value="somecategory3"/>
</productinfos>
</Product>
</Products>
how can i make sure that productinfos category1, category2 or category3 do exist and are not an empty string? And how does the loop look like if i want the following output:
//output
Cat1: somecategory1
Cat3: somecategory3
Cat2: somecategory2
because sometimes the xml i parse looks different:
<?xml version="1.0" standalone="yes"?>
<Products>
<Product>
<name>Milk</name>
<price>1.4</price>
<productinfos>
<category1 value=""/>
<category3 value="somecategory"/>
</productinfos>
</Product>
</Products>
in the above example, how can i check if category2 exists?
tia for your efforts!
You're looking for the SimpleXMLElement::children() method.
https://secure.php.net/manual/en/simplexmlelement.children.php
$xml = new SimpleXMLElement(<<<XML
<?xml version="1.0" standalone="yes"?>
<Products>
<Product>
<name>Milk</name>
<price>1.4</price>
<productinfos>
<category1 value="somecategory1"/>
<category2 value="somecategory2"/>
<category3 value="somecategory3"/>
</productinfos>
</Product>
</Products>
XML
);
// $xml is a SimpleXMLElement of <Products>
foreach ($xml->children() as $product) {
if ($product->getName() != 'Product') {
// ignore <Products><Cow> or whatever, if you care
continue;
}
// start out assuming that everything is missing
$missing_tags = array(
'category1' => true,
'category2' => true,
'category3' => true,
);
// iterate through child tags of <productinfos>
foreach ($product->productinfos->children() as $productinfo) {
// element name is accessed using the getName() method, and
// XML attributes can be accessed like an array
if (isset($missing_tags[$productinfo->getName()]) &&
!empty($productinfo['value'])) {
$missing_tags[$productinfo->getName()] = false;
echo $productinfo->getName() . ": " . $productinfo['value'] . "\n";
}
}
// array_filter with one argument filters out any values that eval to false
if (array_filter($missing_tags)) {
echo "Missing tags: " . implode(", ", array_keys($missing_tags)) . "\n";
}
}
The SimpleXML extension is rather less intuitive than the name would suggest, but it's about as simple as you can get with XML...
Related
first xml
<response status="ok">
<Product>
<name>blbla</name>
<productGroupPrimary>test2</productGroupPrimary>
<productGroupSecondary>test</productGroupSecondary>
<purchasePrice>18</purchasePrice>
<retailPrice>29</retailPrice>
<status>active</status>
<productCode>0001</productCode>
</Product>
<Product>
...
</Product>
other xml
<response status="ok">
<StockQuantityInfo productCode="0001" quantityOnStock="5"></StockQuantityInfo>
<StockQuantityInfo productCode="dhzh" quantityOnStock="5"></StockQuantityInfo>
...
</response>
now i would like to use php to make the final XML document look like this
<response status="ok">
<Product>
<name>blbla</name>
<productGroupPrimary>test2</productGroupPrimary>
<productGroupSecondary>test</productGroupSecondary>
<purchasePrice>18</purchasePrice>
<retailPrice>29</retailPrice>
<status>active</status>
<productCode>0001</productCode>
<stock>5</stock>
</Product>
<Product>
...
</Product>
</response>
i have no idea how i could do this i am a beginner
I tried that foreach
foreach ($xml2->Product as $item2) {
$koda2=$item2->productCode;
foreach ($xml3->StockQuantityInfo as $item3) {
$koda3=$item3->productCode;
if ($koda2 ==$koda3 ) {
$zaloga=$item3->quantityOnStock;
$Product=$xml2->Product->addChild('zaloga',$zaloga);
}
}
the result is that it doesn’t do anything to me, there’s no change, I have a mistake somewhere, or I’m thinking in the wrong direction
I suggest using DOM (not SimpleXML) for this. DOMXpath::evaluate() allows you to fetch the quantity for a product directly using an expression.
// bootstrap the documents
$products = new DOMDocument();
$products->loadXML($productsXML);
$productsXpath = new DOMXpath($products);
$stocks = new DOMDocument();
$stocks->loadXML($stockXML);
$stocksXpath = new DOMXpath($stocks);
// iterate the "Product" elements
foreach ($productsXpath->evaluate('//Product') as $product) {
// get the product code
$code = $productsXpath->evaluate('string(productCode)', $product);
// get the quantity of from the stocks response
$expression = 'number(//StockQuantityInfo[#productCode="'.$code.'"]/#quantityOnStock)';
$quantity = $stocksXpath->evaluate($expression);
// output expression and result for demonstration purposes
var_dump(
$expression, $quantity
);
// validate quantity is a number
if (!is_nan($quantity)) {
// append to "Product"
$product
->appendChild(
$products->createElement('Stock')
)
->textContent = $quantity;
}
}
echo "\n", $products->saveXML();
Output:
string(65) "number(//StockQuantityInfo[#productCode="0001"]/#quantityOnStock)"
float(5)
<?xml version="1.0"?>
<response status="ok">
<Product>
<name>blbla</name>
<productGroupPrimary>test2</productGroupPrimary>
<productGroupSecondary>test</productGroupSecondary>
<purchasePrice>18</purchasePrice>
<retailPrice>29</retailPrice>
<status>active</status>
<productCode>0001</productCode>
<Stock>5</Stock></Product>
</response>
I'm trying to get values from an XML file but i want them to separate in diferrent fields.
My XML file:
<PRODUCTS>
<PRODUCT>
<PRODUCT_NUMBER>7375-06</PRODUCT_NUMBER>
<PRODUCT_NAME>Soft ball</PRODUCT_NAME>
<ITEM_COLOR_NUMBER>04;05;10</ITEM_COLOR_NUMBER>
</PRODUCT>
</PRODUCTS>
My code:
<?php
header ("Content-Type:text/xml");
$xmlA = simplexml_load_file('ftp://.../products.xml');
// create empty output xml object
$final = new simpleXMLElement('<?xml version="1.0" encoding="utf-8"?><PRODUCTINFORMATION></PRODUCTINFORMATION>');
$products = $final->addChild("PRODUCTS");
foreach ($xmlA->PRODUCTS->PRODUCT as $proda) {
$prodbaseno = (string)$proda->PRODUCT_NUMBER;
$prodname = (string)$proda->PRODUCT_NAME;
$prodprintid = (string)$proda->ITEM_COLOR_NUMBER;
// build the output xml
$prodnew = $products->addChild('PRODUCT');
$prodnew->addChild('PRODUCT_NUMBER', $prodbaseno);
$prodnew->addChild('PRODUCT_NAME', $prodname);
$prodnew->addChild('ITEM_COLOR_NUMBER', $prodprintid);
}
echo $final->saveXml();
?>
The output:
<PRODUCTINFORMATION>
<PRODUCTS>
<PRODUCT>
<PRODUCT_NUMBER>MO7375-06</PRODUCT_NUMBER>
<PRODUCT_NAME>Soft ball</PRODUCT_NAME>
<ITEM_COLOR_NUMBER>04;05;10</ITEM_COLOR_NUMBER>
</PRODUCT>
</PRODUCTS>
</PRODUCTINFORMATION>
But what i actually need for ITEM_COLOR_NUMBER is:
<ITEM_COLOR_NUMBER>04</ITEM_COLOR_NUMBER>
<ITEM_COLOR_NUMBER>05</ITEM_COLOR_NUMBER>
<ITEM_COLOR_NUMBER>10</ITEM_COLOR_NUMBER>
How can i set that after a ; create a new ITEM_COLOR_NUMBER with the next value?
You might use explode and use ; as the delimiter.
For example
$prodnew = $products->addChild('PRODUCT');
$prodnew->addChild('PRODUCT_NUMBER', $prodbaseno);
$prodnew->addChild('PRODUCT_NAME', $prodname);
foreach (explode(';', $prodprintid) as $item) {
$prodnew->addChild('ITEM_COLOR_NUMBER', $item);
}
Output
<PRODUCTINFORMATION>
<PRODUCTS>
<PRODUCT>
<PRODUCT_NUMBER>7375-06</PRODUCT_NUMBER>
<PRODUCT_NAME>Soft ball</PRODUCT_NAME>
<ITEM_COLOR_NUMBER>04</ITEM_COLOR_NUMBER>
<ITEM_COLOR_NUMBER>05</ITEM_COLOR_NUMBER>
<ITEM_COLOR_NUMBER>10</ITEM_COLOR_NUMBER>
</PRODUCT>
</PRODUCTS>
</PRODUCTINFORMATION>
Php demo
foreach($resultXML->products->children() as $product) {
echo "<p>".$product->{'advertiser-name'}." - ".$product->price."</p>
<p>".$product->{'description'}."</p>";
}
Suppose I wanted to screen out the ones that had the same title, and only display the first title that appears in the return results.
I'm not working with my own database, this is all about what's displayed.
I suppose the easiest way would be to keep track of the titles in an array, and checking it each iteration.
$titles = array();
foreach($resultXML->products->children() as $product) {
if (in_array($product->title, $titles) continue;
$titles[] = $product->title;
echo "<p>".$product->{'advertiser-name'}." - ".$product->price."</p>
<p>".$product->{'description'}."</p>";
}
Assuming that the title is contained in $product->title. You could do something fancier through array functions, but I don't see a reason to make a simple problem complicated.
You have not provided any exemplary XML, so given for
<?xml version="1.0" encoding="UTF-8"?>
<example>
<products>
<product>
<title>First Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
</products>
<products>
<product>
<title>Second Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
</products>
<products>
<product>
<title>Third Product</title>
<advertiser-name>Second Name</advertiser-name>
</product>
</products>
</example>
You want to get all product elements with an advertiser-name that is not an advertiser-name of all preceding product elements.
So for the XML above, that would be the 1st and 3rd product element.
You can write that down as an XPath expression:
/*/products/product[not(advertiser-name = preceding::product/advertiser-name)]
And as PHP code:
$xml = simplexml_load_string($buffer);
$expr = '/*/products/product[not(advertiser-name = preceding::product/advertiser-name)]';
foreach ($xml->xpath($expr) as $product) {
echo $product->asXML(), "\n";
}
This produces the following output:
<product>
<title>First Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
<product>
<title>Third Product</title>
<advertiser-name>Second Name</advertiser-name>
</product>
So one answer to your question therefore is: Only query those elements from the document you're interested in. XPath can be used for that with SimpleXMLElement.
Related questions:
Implementing condition in XPath
I loop through an XML file. Once I find a certain node I take it's value and change all it's occurrences in the whole document.
XML
<?xml version="1.0" encoding="UTF-8"?>
<catalog catalog-id="my_catalog">
<product product-id="11111111">
......
<new-id>aaaaaaa</new-id>
</product>
<product product-id="2222222">
......
<new-id>bbbbbbb</new-id>
</product>
</catalog>
For each <product> when I find <new-id> I need to replace <product product-id=""> with it which is fine, but also I need to replace all occurrences of 11111111 with aaaaaaa in the whole XML document.
PHP
$cotalog = new SimpleXMLElement($file);
header('Content-Type: text/xml');
foreach ($cotalog as $product) {
if ($product->getName() == 'product') {
$product['product-id'] = $product->{'new-id'};
// code here to replace all occurrences of $product['product-id'] with $product->{'new-id'}
...
}
}
echo $cotalog->asXML();
Is there a str_replace type of way to replace all occurrences of a string value with a different string?
I have been asked to parse a simple file which is stored as an XML file, the data is to be then put into a mysql database.
However I have absolutely no clue what to do and after looking online all the examples given seem either too complicated for my problem or not the right solution. The XML file looks like this:
<shop>
<products>
<product id="1" name="Cornetto" price="1.20" description="Traditional Cornetto" />
<product id="2" name="Smarties" price="1.00" description="Smarties Icecream" />
</products>
<stocks>
<stock id="1" amount="242" price="pounds" />
<stock id="2" amount="11" price="pounds" />
</stocks>
I've tried looking at SimpleXML and I think that's the direction I have to go but I just have no idea.
Any help or pointers would be great.
I personally like the normal XMl formatting so I changed it since its a bit more readable but this is how you can use it:
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<shop>
<products>
<product>
<id>1</id>
<name>Cornetto</name>
<price>1.20</price>
<description>Traditional Cornetto</description>
</product>
<product>
<id>2</id>
<name>Smarties</name>
<price>1.00</price>
<description>Smarties Icecream</description>
</product>
</products>
<stocks>
<stock>
<id>1</id>
<amount>242</amount>
<price>pounds</price>
</stock>
<stock>
<id>2</id>
<amount>11</amount>
<price>pounds</price>
</stock>
</stocks>
</shop>
XML;
Handling part:
$xml = new SimpleXMLElement($xmlstr);
echo 'single value: <br />';
echo $xml->products->product[0]->id; // get single value
echo '<br /><br />';
//Loop trough multiple products
echo 'multiple values: <br />';
foreach($xml->products->product as $product)
{
echo $product->id.' - ';
echo $product->name.' - ';
echo $product->price.' - ';
echo $product->description;
echo '<br/>';
}
Assuming the file is called data.xml
$string = file_get_contents('data.xml') reads the entire file into $string.
$xml = new SimpleXMLElement($string); parses that string, and converts it into an object tree similar to the actual document. So if that's the document -
<root>
<b>
<c>first</c>
<c>second</c>
</b>
</root>
The SimpleXMLElement object would be used like:
$xml->b // gets all children of b (c[0] and c[1])
print $xml->b->c[0] // gets the first c, will print "first"
You can use for example SimpleXMLElement and xpath
<?php
$xmlStr = <<<EOF
<?xml version="1.0"?>
<shop>
<products>
<product id="1" name="Cornetto" price="1.20" description="Traditional Cornetto" />
<product id="2" name="Smarties" price="1.00" description="Smarties Icecream" />
</products>
<stocks>
<stock id="1" amount="242" price="pounds" />
<stock id="2" amount="11" price="pounds" />
</stocks>
</shop>
EOF;
$xml=new SimpleXMLElement($xmlStr);
// get product line with xpath for example
$products=$xml->xpath("/shop/products/product");
if ($products) {
// loop over each product node
foreach ($products as $product) {
// do whatever you want with the data
echo("id=>".$product["id"].", name=>".$product["name"]."<br/>");
}
}
// same for stock
// get product line with xpath for example
$stocks=$xml->xpath("/shop/stocks/stock");
if ($stocks) {
// loop over each product node
foreach ($stocks as $stock) {
// do whatever you want with the data
echo("id=>".$stock["id"].", amount=>".$stock["amount"]."<br/>");
}
}
?>
$xml = simplexml_load_file($filename);
foreach($xml->product as $product) {
foreach($product->attributes() as $name => $attribute) {
echo "$name = $attribute";
}
}
$xml = simplexml_load_file($filename);
foreach($xml->products->product as $not)
{
foreach($not->attributes() as $a => $b)
{
echo $a,'="',$b,"\"<br />";
}
}