I am trying to iterate over set of nodes given by xpath and set certain attribute for each node. However it works only for nodes withou content or with empty (whitespace) content. I have tried 2 approaches but with the same result (maybe they are both the same on some deeper level, dunno). The commented line is the second approach.
$temp = simplexml_load_string (
'<toolbox>
<hammer/>
<screwdriver> </screwdriver>
<knife>
sharp
</knife>
</toolbox>' );
echo "vanilla toolbox: ";
print_r($temp);
$nodes = $temp->xpath('//*[not(#id)]');
foreach($nodes as $obj) {
$tempdom = dom_import_simplexml($obj);
$tempdom->setAttributeNode(new DOMAttr('id', 5));
//$obj->addAttribute('bagr', 5);
}
echo "processed toolbox: ";
print_r($temp);
This is output. Attribute id is missing in node knife.:
vanilla toolbox: SimpleXMLElement Object
(
[hammer] => SimpleXMLElement Object
(
)
[screwdriver] => SimpleXMLElement Object
(
[0] =>
)
[knife] =>
sharp
)
processed toolbox: SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 5
)
[hammer] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 5
)
)
[screwdriver] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 5
)
[0] =>
)
[knife] =>
sharp
I'm unable to reproduce what you describe, the changed XML is:
<?xml version="1.0"?>
<toolbox id="5">
<hammer id="5"/>
<screwdriver id="5"> </screwdriver>
<knife id="5">
sharp
</knife>
</toolbox>
Demo
It's exactly your code, maybe you're using a different LIBXML version? See the LIBXML_VERSION constant (codepad viper has 20626 (2.6.26)).
But probably it's just only the print_r output for a SimpleXMLElement object.
It does not output the attributes for the last element, even on a brand new object, but it's still possible to access the attribute. Demo.
You will see when you print_r($temp->knife['id']); that the attribute is set (as you can see in the earlier XML output).
Related
I am having a problem accessing the #attribute section of my SimpleXML object. When I var_dump the entire object, I get the correct output, and when I var_dump the rest of the object (the nested tags), I get the correct output, but when I follow the docs and var_dump $xml->OFFICE->{'#attributes'}, I get an empty object, despite the fact that the first var_dump clearly shows that there are attributes to output.
Anyone know what I am doing wrong here/how I can make this work?
Try this
$xml->attributes()->Token
You can get the attributes of an XML element by calling the attributes() function on an XML node. You can then var_dump the return value of the function.
More info at php.net
http://php.net/simplexmlelement.attributes
Example code from that page:
$xml = simplexml_load_string($string);
foreach($xml->foo[0]->attributes() as $a => $b) {
echo $a,'="',$b,"\"\n";
}
I used before so many times for getting #attributes like below and it was a little bit longer.
$att = $xml->attributes();
echo $att['field'];
It should be more easy and you can get attributes following format only at once:
Standard Way - Array-Access Attributes (AAA)
$xml['field'];
Other alternatives are:
Right & Quick Format
$xml->attributes()->{'field'};
Wrong Formats
$xml->attributes()->field;
$xml->{"#attributes"}->field;
$xml->attributes('field');
$xml->attributes()['field'];
$xml->attributes->['field'];
$xml = <<<XML
<root>
<elem attrib="value" />
</root>
XML;
$sxml = simplexml_load_string($xml);
$attrs = $sxml->elem->attributes();
echo $attrs["attrib"]; //or just $sxml->elem["attrib"]
Use SimpleXMLElement::attributes.
Truth is, the SimpleXMLElement get_properties handler lies big time. There's no property named "#attributes", so you can't do $sxml->elem->{"#attributes"}["attrib"].
You can just do:
echo $xml['token'];
If you're looking for a list of these attributes though, XPath will be your friend
print_r($xml->xpath('#token'));
It helped me to convert the result of simplexml_load_file($file) into a JSON Structure and decode it back:
$xml = simplexml_load_file("$token.xml");
$json = json_encode($xml);
$xml_fixed = json_decode($json);
$try1 = $xml->structure->{"#attributes"}['value'];
print_r($try1);
>> result: SimpleXMLElement Object
(
)
$try2 = $xml_fixed->structure->{"#attributes"}['value'];
print_r($try2);
>> result: stdClass Object
(
[key] => value
)
Unfortunately I have a unique build (stuck with Gentoo for the moment) of PHP 5.5, and what I found was that
$xml->tagName['attribute']
was the only solution that worked. I tried all of Bora's methods above, including the 'Right & Quick' format, and they all failed.
The fact that this is the easiest format is a plus, but didn't enjoy thinking I was insane trying all of the formats others were saying worked.
Njoy for what its worth (did I mention unique build?).
I want to extract string (just Song title and Artist name) from external xml file: https://nostalgicfm.ro/NowOnAir.xml
This form of xml:
<Schedule System="Jazler">
<Event status="happening" startTime="20:31:20" eventType="song">
<Announcement Display=""/>
<Song title="Let It Be ">
<Artist name="Beatles">
<Media runTime="265.186"/>
<Expire Time="20:35:45"/>
</Artist>
</Song>
</Event>
</Schedule>
I try this code PHP but i don't know how to extract name & title...like "Beatles - Let It Be"
<?php
$url = "https://nostalgicfm.ro/NowOnAir.xml";
$xml = simplexml_load_file($url);
print_r($xml);
?>
Result is an Oject:
SimpleXMLElement Object ( [#attributes] => Array ( [System] => Jazler ) [Event] => SimpleXMLElement Object ( [#attributes] => Array ( [status] => happening [startTime] => 20:51:21 [eventType] => song ) [Announcement] => SimpleXMLElement Object ( [#attributes] => Array ( [Display] => ) ) [Song] => SimpleXMLElement Object ( [#attributes] => Array ( [title] => If You Were A Sailboat ) [Artist] => SimpleXMLElement Object ( [#attributes] => Array ( [name] => Katie Melua ) [Media] => SimpleXMLElement Object ( [#attributes] => Array ( [runTime] => 228.732 ) ) [Expire] => SimpleXMLElement Object ( [#attributes] => Array ( [Time] => 20:55:09 ) ) ) ) ) )
Resolved it myself:
<?php
$url = 'https://nostalgicfm.ro/NowOnAir.xml';
$xml = simplexml_load_file($url);
foreach ( $xml->Event->Song->Artist->attributes() as $tag => $value );
foreach ( $xml->Event->Song->attributes() as $tag => $value1 ) {
echo $value." - ".$value1.PHP_EOL; }
?>
I have a SimpleXMLElement object that I got from parsing a response from oData. I'm looping through the children and it works well as long as it has children (the truth is I'm not even sure if they are its children or if its just a collection). This is how my code looks like:
$dataset = soapService->doSoapCall();
$array = $dataset->children()->children();
foreach($rawArray as $element)
{
$row['Something'] = (string)$element->Something;
$newArr[] = $row;
}
The problem is that this code throws an error of: PHP Node no longer exists SimpleXML. I've been trying to check for null or check the count of it but I keep getting the same error. When I look at it from the debugger in net beans it just says its type SimpleXMLElement but I doesn't have any other value or children. Please help.
Note: When I do print_r($array) i get this:
SimpleXMLElement Object ( )
When the object actually has data it returns this:
SimpleXMLElement Object ( [Table] => Array ( [0] => SimpleXMLElement Object ( [EventCode] => 10020 ) [1] => SimpleXMLElement Object ( [EventCode] => 10030 ) [2] => SimpleXMLElement Object ( [EventCode] => 10040 ) ) ) {"code":99200}
I have searched for this and the answers I find seem to say what I thought I understand. Obviously I am missing something. I am confused at the results from the xPath query. I have simplified my problem for a test case to post here.
My real xml has several dataset nodes at different depths. Ultimately, I want to get every dataset element with a given label and then loop over that and get the field values (at different locations (or depths) so I think I need xpath). I can use xpath to get the dataset elements that I want successfully. However, when I then run xpath on that result object, it gets me the fields I want and all the other fields too. I can't figure out why it isn't only returning field1, field2, and field3. When I print_r($value[0]), it shows only the fields I want. But, when I run xpath on $value[0], it returns all fields in the xml doc.
Sample XML
<myxml>
<dataset label="wanteddata" label2="anotherlabel">
<dataitem>
<textdata>
<field label="label1">field1</field>
<field label="label2">field2</field>
<field label="label3">field3</field>
</textdata>
</dataitem>
</dataset>
<dataset label="unwanteddata" label2="unwantedanotherlabel">
<dataitem>
<textdata>
<field label="label4">field4</field>
<field label="label5">field5</field>
<field label="label6">field6</field>
</textdata>
</dataitem>
</dataset>
</myxml>
Here is the test code.
$xmlstring = file_get_contents('simplexml_test.xml');
$xml = simplexml_load_string($xmlstring);
if ($xml === false) {
throw new Exception("Failed to load");
}
$value = $xml->xpath('//dataset[#label="wanteddata"]');
print_r($value[0]->xpath('//field'));
Code Output:
Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label1
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label2
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label3
)
)
[3] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label4
)
)
[4] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label5
)
)
[5] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label6
)
)
)
//field selects all <field> elements within the entire XML document regardless of the context node from which you call that XPath. To make the XPath heed the context node, you need to add a dot (.) at the beginning of the XPath. In XPath, (.) references current context node :
print_r($value[0]->xpath('.//field'));
I have a XML file simillar to this :
<information version="2">
<currentTime>2014-06-06 17:28:16</currentTime>
<result>
<name>Mark</name>
<surname>Smith</surname>
</result>
I read it with php function and parse it to the object with function, like this:
function parse_data($data){
$return_data['currentTime'] = $data->currentTime;
$return_data['name'] = $data->result->name;
$return_data['surname'] = $data->result->surname;
return $return_data;
}
$xml = simplexml_load_string(file_get_contents($link));
$object = parse_data($xml);
Then, when I echo it on the screen, to check how it look:
//json_encode($xml);
{
"#attributes":{"version":"2"},
"currentTime":"2014-06-06 17:28:16",
"result":{"name":"Mark","surname":"Smith"}
}
//print_r($xml);
SimpleXMLElement Object (
[#attributes] => Array ( [version] => 2 )
[currentTime] => 2014-06-06 17:56:30
[result] => SimpleXMLElement Object (
[name] => Mark
[surname] => Smith
)
)
//json_encode($object);
{
"currentTime":{"0":"2014-06-06 17:28:16"},
"name":{"0":"Mark"},
"surname":{"0":"Smith"}
}
//print_r($object);
Array (
[currentTime] => SimpleXMLElement Object ( [0] => 2014-06-06 17:52:50 )
[name] => SimpleXMLElement Object ( [0] => Mark)
[surname] => SimpleXMLElement Object ( [0] => Smith )
)
What is wrong with my code? He seems to read the informaton in xml file as array? Because of this strange notation I cannont operate on this data normally.
It also behave like this:
echo json_encode($object['name']); will give -> {"0":"Mark"}
echo $object['name']; will give -> Mark
Can anybody help me? What am I doing wrong?
I want my $object to look like this:
//json_encode($object);
{
"currentTime":"2014-06-06 17:28:16",
"name":"Mark",
"surname":"Smith"
}
Edit1: added print_r values
Yes, as you have noticed the type returned by $someSimpleXMLNode is an object. If you want the node value (as a string for example) use:
$return_data['currentTime'] = (string)$data->currentTime;
which is the same as doing
$return_data['currentTime'] = $data->currentTime->__toString();
etc
When you do
echo $data->currentTime;
the node is automatically coerced into a string (because echo only handles strings). This is done (generally, in php) by the object's __toString method.
As I have mentioned in question title, I am trying below code to reach till the desired node in xpath result.
<?php
$xpath = '//*[#id="topsection"]/div[3]/div[2]/div[1]/div/div[1]';
$html = new DOMDocument();
#$html->loadHTMLFile('http://www.flipkart.com/samsung-galaxy-ace-s5830/p/itmdfndpgz4nbuft');
$xml = simplexml_import_dom($html);
if (!$xml) {
echo 'Error while parsing the document';
exit;
}
$source = $xml->xpath($xpath);
echo "<pre>";
print_r($source);
?>
this is the source code. I am using to scrap price from a ecommerce.
it works it gives below output :
Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => line
)
[div] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => prices
[itemprop] => offers
[itemscope] =>
[itemtype] => http://schema.org/Offer
)
[span] => Rs. 10300
[div] => (Prices inclusive of taxes)
[meta] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[itemprop] => price
[content] => Rs. 10300
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[itemprop] => priceCurrency
[content] => INR
)
)
)
)
)
)
Now How to reach till directly [content] => Rs. 10300.
I tried:
echo $source[0]['div']['meta']['#attributes']['content']
but it doesn't work.
Try echo (String) $source[0]->div->meta[0]['content'];.
Basically, when you see an element is an object, you can't access it like an array, you need to use object -> approach.
The print_r of a SimpleXMLElement does not show the real object structure. So you need to have some knowledge:
$source[0]->div->meta['content']
| | | `- attribute acccess
| | `- element access, defaults to the first one
| `- element access, defaults to the first one
|
standard array access to get
the first SimpleXMLElement of xpath()
operation
That example then is (with your address) the following (print_r again, Demo):
SimpleXMLElement Object
(
[0] => Rs. 10300
)
Cast it to string in case you want the text-value:
$rs = (string) $source[0]->div->meta['content'];
However you can already directly access that node with the xpath expression (if that is a single case).
Learn more on how to access a SimpleXMLElement in the Basic SimpleXML usage ExamplesDocs.