PHP iterating over an XML - php

How can I convert XML to an array that I can iterate over.
Here is the example of my XML
<user>
<student>yes</student>
<id>1</id>
<name>John</name>
</user>
<user>
<student>yes</student>
<id>1</id>
<name>Billy</name>
</user>
My php looks like this
$tmpTemplates = new XDomDocument();
$tmpTemplates->load('.....myFile.xml');
$xPath = new DomXPath($tmpTemplates);
$query = "//user[student='yes']";
$tmpTemplate = $xPath->query($query);
What I want to be able to do is
foreach($tmpTemplate as $tt){
var_dump($tt->student);
var_dump($tt->id);
var_dump($tt->name);
}
Now I'm only able to print out nodeValue which gives me something like this:
yes
1
John
How can I make it an array or an object so I can apprach each value by its key?

You used the same id for both records in your example, so I changed the id of the first one and added a document element.
<users>
<user>
<student>yes</student>
<id>2</id>
<name>John</name>
</user>
<user>
<student>yes</student>
<id>1</id>
<name>Billy</name>
</user>
</users>
Use DOMXpath:evaluate() to fetch the details, the second argument is the context node for the expression.
$document = new DOMDocument();
$document->loadXml($xmlString);
$xPath = new DomXPath($document);
$students = [];
foreach ($xPath->evaluate("//user[student='yes']") as $student) {
$id = $xPath->evaluate('string(id)', $student);
$students[$id] = [
'id' => $id,
'name' => $xPath->evaluate('string(name)', $student)
];
}
var_dump($students);
Output:
array(2) {
[2]=>
array(2) {
["id"]=>
string(1) "2"
["name"]=>
string(4) "John"
}
[1]=>
array(2) {
["id"]=>
string(1) "1"
["name"]=>
string(5) "Billy"
}
}
The return value depends on the expression. A location path like //user[student='yes'] or name returns a DOMNodeList. But you can cast the node list directly in Xpath. string(name) will return the contents of the first name child node or an empty string.

How can I make it an array or an object so I can apprach each value by its key?
Just for clarification, you've got an object so far, it's the SimpleXMLElement and you're using then $tt variable to access it:
...
var_dump($tt->student);
var_dump($tt->id);
var_dump($tt->name);
...
Now that $tt variable comes from another variable, namely by iterating over it, and the other variable is named $tmpTemplate:
...
foreach ($tmpTemplate as $tt) {
var_dump($tt->student);
...
That variable by the way is an array. So you can use it by using the index (starting at zero) to access each <user> element containing a <student> child-element with the value "student" in document-order (as you formulated the xpath for it):
$tmpTemplate[0] contains the first user SimpleXMLElement.
$tmpTemplate[1] contains the second user SimpleXMLElement.
... and so on and so forth.
I hope this makes this a bit more visible.

Try with this php function
xml_parse_into_struct
sample from php manual
<?php
$simple = "<para><note>simple note</note></para>";
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
echo "Index array\n";
print_r($index);
echo "\nVals array\n";
print_r($vals);
?>

You can use simplexml_load_file, which convert xml to object.
For instance :
$users = simplexml_load_file("users.xml");
foreach($users as $user) {
...
}

Related

get xml element using php

I have an XML page called (www.example.com/name.xml)
it contains the bellow elements :
<xml>
<names>
<name id='6' >Name 1 </name>
<name id='7'>Name 2</name>
<name id='8'>Name 3</name>
</names>
</xml>
and here is my PHP script :
<?php
$id='6';
$url = "www.example.come/name.xml";
$xml = simplexml_load_file($url);
$position ="$xml->name id='$id' ";
?>
So how can I get it ?
You can simply use xpath for this:
$id='6';
$xml = simplexml_load_file($url);
$position = (string)$xml->xpath("//name[#id='$id']")[0];
echo $position;
Output:
Name 1
This uses xpath to get the text from the <name> where id is 6. Then it casts the SimpleXMLElement to (string), thus providing the output.
Based on your provided data, you could do it like this:
$id='6';
foreach($xml->names->name as $name) {
if ((string)$name->attributes()->id === $id) {
// here $name will be the element for which the attribute id='6'
var_dump($name);
}
}
Will result in:
object(SimpleXMLElement)#3 (2) {
["#attributes"]=>
array(1) {
["id"]=>
string(1) "6"
}
[0]=>
string(7) "Name 1 "
}
$name is of type SimpleXMLElement and the value you are looking for is in the attributes.

How to read xml correctly and get rid of SimpleXMLElement?

I can read an xml input in my code but the output has a SimpleXMLElement property. when I use echo the results has a "SimpleXMLElement ".
how can I delete this term from the out put?
SimpleXMLElement {#253 ▼
+0: "362932"
}
the code is
$xml=simplexml_load_file("$address&league=3");
// dd($xml);
$items = array();
foreach ($xml->Odds as $key => $value)
{
$matchid= ($value->FixtureMatch_Id);
echo "$matchid";
the xml is something like http://www.xmlsoccer.com/FootballDataDemo.asmx/GetFixtureMatchByID?ApiKey=ZXRIQOWMCFARAWRQIMSLRXCTSZDOBNLOTYWXYXMZYGDSENFSRB&Id=362933.
I want to eliminate SimpleXMLElement from the output.
You simply need to cast it into a string. SimpleXMLElement implements several interfaces and magic methods. For example Traversable to allow for foreach() and __toString() for string casting.
An echo is an implicit string cast, so it will output only the text content.
Here is a small example with a stripped down XML:
$xml = <<<'XML'
<?xml version="1.0" encoding="utf-8"?>
<XMLSOCCER.COM>
<Match>
<Id>362933</Id>
</Match>
</XMLSOCCER.COM>
XML;
$soccer = new SimpleXMLElement($xml);
foreach ($soccer->Match as $match) {
$matchId = $match->Id;
var_dump($matchId);
var_dump((string)$matchId);
echo $matchId;
}
Output:
object(SimpleXMLElement)#5 (1) {
[0]=>
string(6) "362933"
}
string(6) "362933"
362933
As you can see the property is a SimpleXMLElement (first var_dump()). But it can be cast into a string (second var_dump()) and an echo triggers an implicit cast.

PHP simpleXML get value of different nodes depending on value

I have the following XML code:
<administration>
<notes>
<note>
<id>12312312</id>
<name>Lorem Ipsum</name>
<reference>Target Value - 1</reference>
</note>
<note>
<id>12312365</id>
<name>Lorem Ipsum</name>
<references>
<code>Dolor it se met.</code>
<code>Target Value - 2</code>
</references>
</note>
<note>
<id>12375512</id>
<name>Target Value - 3</name>
<reference>S</reference>
</note>
</notes>
<accounting>
<ledgers>
<ledger>
<debits>
<debit>
<description>Target Value - 4</description>
<amount>5467.32</amount>
</debit>
<debit>
<description>My Debit</description>
<amount>5467.32</amount>
<tags>
<tag>Target Value - 5</tag>
</tags>
</debit>
</debits>
<credits>
<credit>
<title>Target Value - 6</title>
<amount>873.00</amount>
</credit>
<credit>
<description>Target Value - 7</description>
<amount>23454.12</amount>
</credit>
</credits>
</ledger>
</ledgers>
</accounting>
</administration>
I'm trying to get a PHP array which consists of only the values of the nodes which have a value containing this string: "Target Value".
This has to be done on a recursive way, using an XML parser (I'm trying SimpleXML, but I'm new to that).
Up 'till now, I've been trying to use SimpleXmlIterator and foreach- and for-loops to achieve this, but I can't seem to check if a node value contains "Target Value".
Edit: reaching the target nodes by manually referring to them is not what I'm looking for, if I were, there would be no problem
Is there any way to achieve this?
EDIT:
Here is the code of my last try:
function sxiToArray($sxi)
{
$a = array();
for( $sxi->rewind(); $sxi->valid(); $sxi->next() )
{
if(!array_key_exists($sxi->key(), $a))
{
$a[$sxi->key()] = array();
}
if($sxi->hasChildren())
{
if (strpos((string)$sxi->current(), "Target Value"))
$a[$sxi->key()][] = sxiToArray($sxi->current());
}
else
{
if (strpos((string)$sxi->current(), "Target Value"))
$a[$sxi->key()][] = strval($sxi->current());
}
}
return $a;
}
$xmlArray = xml2array('../Document.xml');
print_r($xmlArray);
This gives the following result after running:
Array ( [notes] => Array ( ) [accounting] => Array ( ) )
It does not have to be done in an recursive way. You can use Xpath. Xpath uses location paths as part of an expression. The paths use different axes - one of them is descendant. It "ignores" the nesting. Xpath allows you to use conditions.
Get any element node in the document
//*
That has a text node as an child
//*[./text()]
with the text node containing the string "Target Value"
//*[./text()[contains(., "Target Value")]]
Put together it is a fairly small piece of code:
$administration = new SimpleXMLElement($xml);
$nodes = $administration->xpath('//*[./text()[contains(., "Target Value")]]');
foreach ($nodes as $node) {
var_dump($node->getName(), (string)$node);
}
Output:
string(9) "reference"
string(16) "Target Value - 1"
string(4) "code"
string(16) "Target Value - 2"
string(4) "name"
string(16) "Target Value - 3"
string(11) "description"
string(16) "Target Value - 4"
string(3) "tag"
string(16) "Target Value - 5"
string(5) "title"
string(16) "Target Value - 6"
string(11) "description"
string(16) "Target Value - 7"
And with DOM it would not look much different:
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$nodes = $xpath->evaluate('//*[./text()[contains(., "Target Value")]]');
foreach ($nodes as $node) {
var_dump($node->localName, $node->textContent);
}
Why don't you try str_pos() for "Target value"? I don't exactly know how you iterate through the XML but you could do something like:
if(str_pos($node, "Target value"){
//do whatever
}
That will tell you if any of the nodes at least contain that specific string.

Extract Data off multiple XML row

I have a really weird XML response and i need to extract it's data. I need to get the data in the "value" attribute but i need to choose them according to their "key" attributes.
This is how it looks like
<phone>
2125556666
</phone>
<State>
ny
</State>
<Response>
<data key="Supported" value="Yes"/>
<data key="Host" value="Remote"/>
<data key="WholeProductList">
<data key="Product" value="a-z44"/>
<data key="Product" value="c-k99"/>
<data key="Product" value="e-b089"/>
<data key="Product" value="z-p00"/>
<data key="Product" value="r-333"/>
<data key="Product" value="t-RS232"/>
<data key="Product" value="4-lve"/>
<data key="Product" value="Shutdown"/>
</data>
</Response>
In PHP i currenty have
$xmltmp = new DomDocument;
$xmltmp->loadXml($response);
$phone = $xmlresponse->getElementsByTagName('phone')->item(0)->nodeValue;
$state = $xmlresponse->getElementsByTagName('state')->item(0)->nodeValue;
echo $phone;
echo $state;
This currently outputs both phone number and state. It works fine.
Now i need to know if the "Supported" key's value is Yes or No, and if it's Yes, i need to get all "Products". I'm kinda stuck because i am having a hard time making the foreach statement and then checking the "key" attribute value.
Thanks!
Your XML is invalid. An XML document always needs a single document element node.
Example:
<root>
<phone>2125556666</phone>
<State>ny</State>
<Response>
<data key="Supported" value="Yes"/>
...
</data>
</Response>
</root>
The easiest way to fetch data from a DOM is XPath. In PHP that is provided by the DOMXPath class and part of the ext/dom. DOMXPath::evaluate() allows you to fetch node lists or scalar values from the DOM document.
$dom = new DOMDocument;
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$phone = $xpath->evaluate('string(/*/phone)');
$state = $xpath->evaluate('string(/*/State)');
var_dump($phone, $state);
Output:
string(10) "2125556666"
string(2) "ny"
An expression like /*/phone selects all phone element child nodes inside the document element. string(/*/phone) casts the first found node into a string and return that. If no node was found, it will return an empty string.
The XPath expression for the supported status is slightly more complex. Conditions for nodes are provided in []. It is possible to compare the result directly in XPath. The return value will be an boolean.
$supported = $xpath->evaluate('/*/Response/data[#key="Supported"]/#value = "Yes"');
var_dump($supported);
Output:
bool(true)
If the expression returns a node list you can iterate it with foreach().
$nodes = $xpath->evaluate(
'/*/Response/data[#key="WholeProductList"]/data[#key="Product"]/#value'
);
$products = [];
foreach ($nodes as $attributeNode) {
$products[] = $attributeNode->value;
}
var_dump($products);
Output:
array(8) {
[0]=>
string(5) "a-z44"
[1]=>
string(5) "c-k99"
[2]=>
string(6) "e-b089"
[3]=>
string(5) "z-p00"
[4]=>
string(5) "r-333"
[5]=>
string(7) "t-RS232"
[6]=>
string(5) "4-lve"
[7]=>
string(8) "Shutdown"
}
This won't quite work "as is" since I don't know what the actual structure of the XML document is, but in short you map the XML nodes to XPath like //root/node/child_node/#attribute and so on.
It should also have some sanity (not null) type checking in.
$xmltmp = new DomDocument;
$xmltmp->loadXml($response);
$xQuery = new DOMXPath($xmltmp);
//not sure what your root node is so the query path is probably wrong
$supported = $xQuery->query('/Response/data[#key="Supported"]/#value')->value;
You can also replace:
$phone = $xmlresponse->getElementsByTagName('phone')->item(0)->nodeValue;
$state = $xmlresponse->getElementsByTagName('state')->item(0)->nodeValue;
With something like (again - without the full structure of the XML document the path itself is probably not quite right):
$phone = $xQuery->query('/phone')->item(0)->nodeValue;
$state = $xQuery->query('/State')->item(0)->nodeValue;

xml export php code returns only one parent of the xml file i need them all

$rss_tags = array(
'drawNo',
'drawTime',
'result',
);
$rss_item_tag = 'draw';
$rss_url = "http://applications.opap.gr/DrawsRestServices/kino/drawDate/21-12-2014.xml";
$rssfeed = rss_to_array($rss_item_tag,$rss_tags,$rss_url);
echo '<pre>';
print_r($rssfeed);
/*$total=1;
foreach($rssfeed as $item)
{
if($total<750){
echo '<div><h1>Κλήρωση: '.$item['drawNo']. ' Αριθμοί: ' .$item['result'].'</h1></div>';
$total++;
}
}
*/
function rss_to_array($tag, $array, $url) {
$doc = new DOMdocument();
$doc->load($url);
$rss_array = array();
$items = array();
foreach($doc->getElementsByTagName($tag) AS $node) { //se auth thn epanalhpsh epanalamvenete toses fores oses oi klhrwseis tis hmeras
foreach($array AS $key => $value) { //$array einai ta rss tags
if($value=="result"){
for($i=1;$i<=20;$i++){$items["result"] = $node->getElementsByTagName("result")->item(0)->nodeValue;}
}
$items[$value] = $node->getElementsByTagName($value)->item(0)->nodeValue;
}
array_push($rss_array, $items);
}
return $rss_array;
}
Hello phpers, this is my code to read some xml information but i have a big big big problem.
Firstly check the xml source:
http://applications.opap.gr/DrawsRestServices/kino/drawDate/21-12-2014.xml
The structure is like that:
<draws>
<draw>
<drawNo>
<drawTime>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
<result>
and my code returns only the first entry of the but i want to get both 20 entries could someone help me?
I'm not sure what exactly do you want to output, but maybe this will suit your purpose.
The code below converts xml to array.
<?php
$xmlstring = file_get_contents("http://applications.opap.gr/DrawsRestServices/kino/drawDate/21-12-2014.xml");
// converts $xmlstring to multidimensional array
$arrayMD = json_decode(json_encode((array) simplexml_load_string($xmlstring)), true);
echo "<pre>";
var_dump($arrayMD);
echo "</pre>";
// converts multidimensional array to one-dimensional array
// in other words: "flattens" a multidimensional array
$array = new RecursiveIteratorIterator(new RecursiveArrayIterator($arrayMD));
foreach($array as $v) {
echo $v . "<br>";
}
?>
The output would be as follows:
array(1) {
["draw"]=>
array(157) {
[0]=>
array(3) {
["drawNo"]=>
string(6) "475781"
["drawTime"]=>
string(25) "2014-12-21T09:00:00+02:00"
["result"]=>
array(20) {
[0]=>
string(1) "6"
[1]=>
string(1) "7"
[2]=>
string(2) "12"
[3]=>
string(2) "13"
[4]=>
string(2) "15"
[5]=>
string(2) "16"
...
Reference:
simplexml_load_string
json_encode
json_decode (When second parameter is set to TRUE, returned objects will be converted into associative arrays.)
JSON Predefined Constants
(array) - cast to array, Type Juggling
How to Flatten a Multidimensional Array?
Update:
To access some specific element of the multidimensional array:
$someVar = $arrayMD["draw"][0]["result"][7];
echo $someVar; // outputs: 12
Additionally, have a look at the list function (assigns variables as if they were an array) or extract (imports variables into the current symbol table from an array).
Or the easiest way is just to use several foreach to output them, sum the numbers, select every fifth "result" value of every "draw" or anything else. (This depends on what are you going to do with those values next.)

Categories