How do i convert an associate array to an XML string? I found this but get the error 'Call to a member function addChild() on a non-object' when running the line
$node = $xml->addChild($key);
Use the PHP Document Object Model:
$xml = new DOMDocument('1.0', 'utf-8');
$root = $xml->createElement('top');
$xml->appendChild($root);
foreach ($arr as $k => $v) {
$node = $xml->createelement($k);
$text = $xml->createTextNode($v);
$node->appendChild($text);
$root->appendChild($node);
}
echo $xml->saveXml();
Did you initialize the $xml object? That's probably your problem.
Its pretty similar to how you would do something like this:
while($row = mysql_fetch_assoc($result))
You can't use $result as an array, but you can foreach or while through the different entries.
PEAR's XML_Serialize is pretty good if you want a easy solution. Doing the DOM manually is arguably faster.
Related
I'm after a way of making simplexml_load_string return a document where all the text values are urldecoded. For example:
$xmlstring = "<my_element>2013-06-19+07%3A20%3A51</my_element>";
$xml = simplexml_load_string($xmlstring);
$value = $xml->my_element;
//and value would contain: "2013-06-19 07:20:51"
Is it possible to do this? I'm not concerned about attribute values, although that would be fine if they were also decoded.
Thanks!
you can run
$value = urldecode( $value )
which will decode your string.
See: http://www.php.net/manual/en/function.urldecode.php
As long as each value is inside an element of its own (in SimpleXML you can not process text-nodes on its own, compare with the table in Which DOMNodes can be represented by SimpleXMLElement?) this is possible.
As others have outlined, this works by applying the urldecode function on each of these elements.
To do that, you need to change and add some lines of code:
$xml = simplexml_load_string($xmlstring, 'SimpleXMLIterator');
if (!$xml->children()->count()) {
$nodes = [$xml];
} else {
$nodes = new RecursiveIteratorIterator($xml, RecursiveIteratorIterator::LEAVES_ONLY);
}
foreach($nodes as $node) {
$node[0] = urldecode($node);
}
This code-example takes care that each leave is processed and in case, it's only the root element, that that one is processed. Afterwards, the whole document is changed so that you can access it as known. Demo:
<?php
/**
* URL decode all values in XML document in PHP
* #link https://stackoverflow.com/q/17805643/367456
*/
$xmlstring = "<root><my_element>2013-06-19+07%3A20%3A51</my_element></root>";
$xml = simplexml_load_string($xmlstring, 'SimpleXMLIterator');
$nodes = $xml->children()->count()
? new RecursiveIteratorIterator(
$xml, RecursiveIteratorIterator::LEAVES_ONLY
)
: [$xml];
foreach ($nodes as $node) {
$node[0] = urldecode($node);
}
echo $value = $xml->my_element; # prints "2013-06-19 07:20:51"
Is it possible to change a sub-string of an object element
in the flow inside of a foreach loop? So what I try but it's not working.
$xml= '';
foreach ($objetcs as $object){
str_replace('searched','replacement', $object->link);
//then I would call a function to render my rss
$xml .=$object->renderRSS();
}
str_replace will return a string or an array, it won't change original variable, so you should do $object->link = str_replace('searched','replacement', $object->link); if $link is public
Try this:
$xml= '';
foreach ($objetcs as $object){
$object->link = str_replace('searched','replacement', $object->link);
//then I would call a function to render my rss
$xml .=$object->renderRSS();
}
Try:
$object->link = str_replace('searched','replacement', $object->link);
I am having a heck of a time getting this working...
What I want to do is filter a xml file by a city (or market in this case).
This is the xml data.
<itemset>
<item>
<id>2171</id>
<market>Vancouver</market>
<url>http://</url></item>
<item>
<id>2172</id>
<market>Toronto</market>
<url>http://</url></item>
<item>
<id>2171</id>
<market>Vancouver</market>
<url>http://</url></item>
This is my code...
<?php
$source = 'get-xml-feed.php.xml';
$xml = new SimpleXMLElement($source);
$result = $xml->xpath('//item/[contains(market, \'Toronto\')]');
while(list( , $node) = each($result)) {
echo '//Item/[contains(Market, \'Toronto\')]',$node,"\n";
}
?>
If I can get this working I would like to access each element, item[0], item[1] base on filtered results.
Thanks
I think this implements what you are looking for using XPath:
<?php
$source = file_get_contents('get-xml-feed.php.xml');
$xml = new SimpleXMLElement($source);
foreach ($xml as $node)
{
$row = simplexml_load_string($node->asXML());
$result = $row->xpath("//item/market[.='Toronto']");
if ($result[0])
{
var_dump($row);
}
}
?>
As another answer mentioned, unless you are wed to the use of XPath it's probably more trouble than it's worth for this application: just load the XML and treat the result as an array.
I propose using simplexml_load_file. The learning curve is less step than using the specific XML objects + XPath. It returns an object in the format you descibe.
Try this and you'll see what I mean:
<?php
$source = 'get-xml-feed.php.xml';
$xml = simplexml_load_file($source);
var_dump($xml);
?>
There is also simplexml_load_string if you just have an XML snippet.
<?php
$source = 'get-xml-feed.php.xml';
//$xml = new SimpleXMLElement($source);
$dom = new DOMDocument();
#$dom->loadHTMLFile($source);
$xml = simplexml_import_dom($dom);
$result = $xml->xpath("//item/market[.='Toronto']/..");
while(list( , $node) = each($result)) {
print_r($node);
}
?>
This will get you the parent nodeset when it contains a node with "Toronto" in it. It returns $node as a simplexml element so you will have to deal with it accordingly (I just printed it as an array).
probably a simple question to answer for someone:::
xml:
<foobar>
<foo>i am a foo</foo>
<bar>i am a bar</bar>
<foo>i am a <bar>bar</bar></foo>
</foobar>
In the above, I want to display all elements that are <foo>. When the script gets to the line with the nested < bar > the result is "i am a bar" .. which isn't the result I had hoped for.
Is it not possible to print out the entire contents of that element as it is, so that i see: "i am a <bar>bar</bar>"
php:
$xml = file_get_contents('sample');
$dom = new DOMDocument;
#$dom->loadHTML($xml);
$resources= $dom->getElementsByTagName('foo');
foreach ($resources as $resource){
echo $resource->nodeValue . "\n";
}
After some trolling and trying to do what I needed with SimpleXML, I arrived at the following conclusion. My issue with SimpleXML was where the elements are. If the xml is structured, and the hierarchy is standard ... I have no problem.
If the XML is a web page for example, and the <foo> element is anywhere, SimpleXML doesn't have a good facility like getElementsByTagName to pull out the element wherever it may be....
<?php
$doc = new DOMDocument();
$doc->load('sample');
$element_name = 'foo';
if ($doc->getElementsByTagName($element_name)->length > 0) {
$resources = $doc->getElementsByTagName($element_name);
foreach ($resources as $resource) {
$id = null;
if (!$resource->hasAttribute('id')) {
$resource->setAttribute('id', gen_uuid());
}
$innerHTML = null;
$children = $resource->childNodes;
foreach ($children as $child) {
$tmp_doc = new DOMDocument();
$tmp_doc->appendChild($tmp_doc->importNode($child,true));
$innerHTML .= rtrim($tmp_doc->saveHTML());
}
$resource->nodevalue = $innerHTML;
}
}
echo $doc->saveHTML();
?>
Rather than writing all that code, you might try XPath. That expression would be "//foo", which would get a list of all the elements in the document named "foo".
http://php.net/manual/en/simplexmlelement.xpath.php
I know how to use simplexml_load_file to get XML results if the XML format is
<bowlcontents>
<banana>yellow</banana>
<apple>red</apple>
</bowlcontents>
However, I have some code that is in the format
<bowlcontents>
<fruit type="banana" skin="yellow" />
<fruit type="apple" skin="red" />
</bowlcontents>
and I want to manipulate it in the same way as in the first example. How would I do this?
EDIT: This is precisely what I want to do, yet the code below doesn't work.
<?php
$url = "http://worldsfirstfruitAPI.com/fruit.xml";
$xml = (simplexml_load_file($url));
$results = array();
foreach ($xml->bowlcontents->fruit as $fruit) {
$results[] = array(
$fruit['type'] => $fruit['skin'],
);
}
return $results;
}
?>
So at the end of it I would like to have an array, key=value:
banana=yellow
apple=red
...
I hope this clarifies. Thanks!
As per PHP's manual, attributes are accessed using the array notation:
$bowlcontents->fruit['type'];
Come to think of it, you didn't say in your question what was your problem. If that's about iterating over nodes, you can do it using foreach.
/*
$bowlcontents = simplexml_load_string(
'<bowlcontents>
<fruit type="banana" skin="yellow" />
<fruit type="apple" skin="red" />
</bowlcontents>'
);
*/
$url = "http://worldsfirstfruitAPI.com/fruit.xml";
$bowlcontents = simplexml_load_file($url);
foreach ($bowlcontents->fruit as $fruit)
{
echo $fruit['type'], "'s skin is ", $fruit['skin'], "<br/>\n";
}