I have this kind of XML:
<?xml version="1.0" encoding="utf-8"?>
<data>
<stats>
</stats>
<params>
</params>
<results>
<record id='SJDGH'>
<item>abc</item>
<item>def</item>
<item>ghi</item>
</record>
<record id='OIIO'>
<item>abc</item>
<item>def</item>
<item>ghi</item>
</record>
</results>
</data>
I'm generating a new <item> for every <record> in <results> in a loop:
// $data is SimpleXml objec from XML above
foreach ($data->results->record as $record)
{
$newitem = 'New item!'.time().$record->attributes()->id;
}
Somehow in this loop i need to change the SimpleXML object ($data) to contain new items in every <record>.
is it possible?
I needed a little guessing, but this might what you're looking for:
$records = $data->results->record;
foreach($records as $record)
{
$value = sprintf('New Item! %s / id:%s', time(), $record['id']);
$record->item[] = $value;
}
$data->asXML('php://output');
See it in action.
I think you might want to use addChild.
Check it out here: http://php.net/manual/en/simplexmlelement.addchild.php
Related
I have an XML file:
<include>
<data>
<name>Chicken</name>
<price>1</price>
</data>
<data>
<name>Fish</name>
<price>5</price>
</data>
...Cut off about 100 lines...
<data>
<name>Pig</name>
<price>105</price>
</data>
<include>
Now, I want to add the ascending <id>, right above the <name> like this:
<include>
<data>
<id>1203001</id>
<name>Chicken</name>
<price>1</price>
</data>
<data>
<id>1203002</id>
<name>Fish</name>
<price>5</price>
</data>
...Cut off about 100 lines...
<data>
<id>1203105</id>
<name>Pig</name>
<price>105</price>
</data>
<include>
I used the for loop, here is my code:
$data = <<<XML
<include>
<data>
<name>Chicken</name>
<price>1</price>
</data>
<data>
<name>Fish</name>
<price>5</price>
</data>
...Cut off about 100 lines...
<data>
<name>Pig</name>
<price>105</price>
</data>
<include>
XML;
for($i = 1203001; $i <= 1203105; $i++) {
$xml = new SimpleXMLElement($data);
$xml->data->addChild("id", $i);
}
echo $xml->asXML();
However, the result I get is that <id> only appears once, with the largest value, next to </data> instead of the position I want::
<include>
<data>
<name>Chicken</name>
<price>1</price>
<id>1203105</id></data>
<data>
<name>Fish</name>
<price>5</price>
</data>
...
Please show me a method to solve this problem. I would appreciate your solution.
You're recreating $xml from $data every time through the loop, so you're discarding the changes you made on the previous iteration.
Initialize $xml before the loop. Then loop over the data child nodes.
$xml = new SimpleXMLElement($data);
$i = 1203001;
foreach ($xml->data as $node) {
$node->addChild("id", $i++);
}
If you want to insert <id> at the beginning of the <data> node instead of the end, see SimpleXML how to prepend a child in a node?
i know a few about php, so sorry for the question:
i have this file xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<alert>
<status> </status>
<nothing> </nothing>
<info>
<area>
</area>
</info>
<info>
<area>
</area>
</info>
<info>
<area>
</area>
</info>
</alert>
i must do a for loop and inside a "foreach" for each
The problem is that i'm not sure what is a way to know how many times i had to repeat a for loop. Because in this file xml (that is an example) i don't know how many are
Is good if:
$url = "pathfile";
$xml = simplexml_load_file($url);
$numvulcani = count($xml->alert->info); // is good ?
for ($i = 0; $i <= $numvulcani; $i++) {
foreach ($xml->alert->info[$i] as $entry) {
$area = $entry->area;
}
}
is true ?
sorry for bad english
You need to use SimpleXMLElement::count function for this — It counts the children of an element.
<?php
$xml = <<<EOF
<people>
<person name="Person 1">
<child/>
<child/>
<child/>
</person>
<person name="Person 2">
<child/>
<child/>
<child/>
<child/>
<child/>
</person>
</people>
EOF;
$elem = new SimpleXMLElement($xml);
foreach ($elem as $person) {
printf("%s has got %d children.\n", $person['name'], $person->count());
}
?>
The output will be as follows :
Person 1 has got 3 children.
Person 2 has got 5 children.
Also take a look at this link : xml count using php
Try replacing foreach ($xml->alert->info[$i] as $entry) with:
foreach ($xml->alert->info[$i] as $j => $entry)
The current item index will be $j
You're perhaps overcomplicating this a bit as it's new to you.
First of all, you don't need to reference the alert root element like $xml->alert because the SimpleXMLElement named by the variable $xml represents that document element already.
And second, you don't need to count here, you can just foreach directly:
foreach ($xml->info as $info) {
echo ' * ', $info->asXML(), "\n";
}
This iterates over those three info elements that are children of the alert element.
I recommend the Basic SimpleXML usage guide in the PHP manual for a good start with SimpleXML.
I am trying to get the PAY where it has the ID 3 Where it says the label phone
but i really dont know how, i tried everything.
Thanks for helping!
Here is the XML code:
$books = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data>
<login>1</login>
<arrStatsData>
<item>
<Id>500</Id>
<Label>website_name</Label>
<Data>
<item>
<Id>4</Id>
<Label>transactions</Label>
<Data>
<sum>2029.34</sum>
<cst>47.67575</cst>
<num>86</num>
<avg>23.6</avg>
<pay>1981.66</pay>
</Data>
</item>
<item>
<Id>3</Id>
<Label>Phone</Label>
<Data>
<sum>205</sum>
<cst>17.353</cst>
<num>205</num>
<avg>1</avg>
<pay>187.647</pay>
</Data>
</item>
......
PHP Code:
$xml = simplexml_load_string($arrResult); //load xml from above
foreach($xml->arrStatsData->item->Data as $item)
{
foreach($item->item as $DATA)
{
echo $DATA->Id.'<br>';
}
My result now is:
1981.66
187.647
-0.4448
Since you know some information that's tell the node apart from the rest you can use XPath to get the value directly instead of iterating through all of them:
<?php
$sxe = new SimpleXMLElement($books);
$pay = $sxe->xpath('//item[./Id=3]/Data/pay');
echo (string) $pay[0];
Ouput:
187.647
Your PHP code would be like this:
$xml = simplexml_load_string($books);
foreach($xml->arrStatsData->item->Data as $item)
{
//echo '$item;';
foreach($item->item as $DATA)
{
if($DATA->Id == '3'){
echo $DATA->Data->pay."<br/>";
}
}
}
It retrieve the pay value when the ID is equals to 3.
Rolando Isidoro was faster to recommend xpath, my solution is slightly different, that's why I post it, too:
$pay = (string)$xml->xpath("//item[Id = '3']/Data/pay")[0];
echo $pay;
see it working: http://codepad.viper-7.com/qzPlmp
I need to get <name> and <URL> tag's value where subtype="mytype".How can do it in PHP?
I want document name and test.pdf path in my result.
<?xml version="1.0" encoding="UTF-8"?>
<test>
<required>
<item type="binary">
<name>The name</name>
<url visibility="restricted">c:/temp/test/widget.exe</url>
</item>
<item type="document" subtype="mytype">
<name>document name</name>
<url visiblity="visible">c:/temp/test.pdf</url>
</item>
</required>
</test>
Use SimpleXML and XPath, eg
$xml = simplexml_load_file('path/to/file.xml');
$items = $xml->xpath('//item[#subtype="mytype"]');
foreach ($items as $item) {
$name = (string) $item->name;
$url = (string) $item->url;
}
PHP 5.1.2+ has an extension called SimpleXML enabled by default. It's very useful for parsing well-formed XML like your example above.
First, create a SimpleXMLElement instance, passing the XML to its constructor. SimpleXML will parse the XML for you. (This is where I feel the elegance of SimpleXML lies - SimpleXMLElement is the entire library's sole class.)
$xml = new SimpleXMLElement($yourXml);
Now, you can easily traverse the XML as if it were any PHP object. Attributes are accessible as array values. Since you're looking for tags with specific attribute values, we can write a simple loop to go through the XML:
<?php
$yourXml = <<<END
<?xml version="1.0" encoding="UTF-8"?>
<test>
<required>
<item type="binary">
<name>The name</name>
<url visibility="restricted">c:/temp/test/widget.exe</url>
</item>
<item type="document" subtype="mytype">
<name>document name</name>
<url visiblity="visible">c:/temp/test.pdf</url>
</item>
</required>
</test>
END;
// Create the SimpleXMLElement
$xml = new SimpleXMLElement($yourXml);
// Store an array of results, matching names to URLs.
$results = array();
// Loop through all of the tests
foreach ($xml->required[0]->item as $item) {
if ( ! isset($item['subtype']) || $item['subtype'] != 'mytype') {
// Skip this one.
continue;
}
// Cast, because all of the stuff in the SimpleXMLElement is a SimpleXMLElement.
$results[(string)$item->name] = (string)$item->url;
}
print_r($results);
Tested to be correct in codepad.
Hope this helps!
You can use the XML Parser or SimpleXML.
I have an xml document with the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<url>www.test.com</url>
</item>
<item>
<id>2</id>
<url>www.test2.com</url>
</item>
</items>
I would like to be able to search for a node value, such as the value of 1 for the id field. Then, once that node is found, select the parent node, which would be < item > and insert a new child within.
I know the concept of using dom document, but not sure how to do it in this instance.
This should be a start:
$dom = new DOMDocument;
$dom->loadXML($input);
$ids = $dom->getElementsByTagName('id');
foreach ($ids as $id) {
if ($id->nodeValue == '1') {
$child = $dom->createElement('tagname');
$child->appendChild($dom->createTextNode('some text'));
$id->parentNode->appendChild($child);
}
}
$xml = $dom->saveXML();
or something close to it.
You can do the same thing in a simpler way. Instead of looking for an <id/> node whose value is 1 then selecting its parent, you can reverse the relation and look for any node which has an <id/> child whose value is 1.
You can do that very easily in XPath, and here's how to do it in SimpleXML:
$items = simplexml_load_string(
'<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<url>www.test.com</url>
</item>
<item>
<id>2</id>
<url>www.test2.com</url>
</item>
</items>'
);
$nodes = $items->xpath('*[id = "1"]');
$nodes[0]->addChild('new', 'value');
echo $items->asXML();