I'm trying to edit a node value while in a loop. I can edit nodes with unique names just fine.
$gdNodes->orgName = 'test';
But when I'm in a loop, the value is not saved when I output my XML.
foreach($gdNodes->phoneNumber as $phone)
{
$phone = '1234567';
}
Both are SimpleXMLElement class objects. I don't understand why it's not saving. How is it done?
It won't save because $phone is a scalar copy of the original value.
You should be able to reach your goal like this:
foreach($gdNodes->phoneNumber as $key => $phone)
{
$gdNodes->phoneNumber[$key] = '1234567';
}
Related
I need to save some values from XML.
First step - I get the structure:
$xml = $dom_xml->saveXML();
$xml_ = new \SimpleXMLElement($xml);
dd($xml_);
Here TextFrame has 8 arrays. Each of them has PathPointType, which has
4 more arrays with 3 attributes each. And these attributes I need from each TextFrame.
I can get, for instance, Anchor value doing this:
$res = $xml_
->Spread
->TextFrame
->Properties
->PathGeometry
->GeometryPathType
->PathPointArray
->PathPointType
->attributes();
dd($res['Anchor']);
(BTW: is there more prettier way to get it?)
But the question is - how is it possible to loop through all arrays and save values separately for each array?
I assume here has to be a multidimensional foreach loop in conjunction with for loop?
Or is better to achieve it using DOMDocument?
As it looks as though you are starting off with DOMDocument (as you are using $dom_xml->saveXML() to generate the XML), it may be easier to continue using it and it also has some easy features for getting the details your after.
Using getElementsByTagName() allows you to get a list of the elements with a specific tag name from a start point, so starting with $dom_xml, get all of the <TextFrame> elements. Then foreach() over this list and using this element as a start point, use getElementsByTagName("PathPointType") to get the nested <PathPointType> elements. At this point you can then use getAttribute("Anchor") for each of the attributes you need from the <PathPointType> elements...
$textFrames = $dom_xml->getElementsByTagName("TextFrame");
foreach ( $textFrames as $frame ) {
$pathPointTypes = $frame->getElementsByTagName("PathPointType");
foreach ( $pathPointTypes as $type ) {
echo $type->getAttribute("Anchor").PHP_EOL;
}
}
Edit
You can extend the code to build an array of frames and then the anchors within that. This code also stores the anchor in an associative array so that if you add the other attributes, you can add them here (or remove it if you don't need another layer of detail)...
$frames =[];
foreach ( $textFrames as $frame ) {
$anchors = [];
$pathPointTypes = $frame->getElementsByTagName("PathPointType");
foreach ( $pathPointTypes as $type ) {
$anchors[] = ['Anchor' => $type->getAttribute("Anchor")];
}
$frames[] = $anchors;
}
Also if you have some way of identifying the frames, you could create an associative array at that level as well...
$frames[$frameID] = $anchors;
As a complement to the existing answer from Nigel Ren, I thought I'd show how the same loops look with SimpleXML.
Firstly, note that you don't need to convert the XML to string and back if you want to switch between DOM and SimpleXML for any reason, you can use simplexml_import_dom which just swaps out the interface:
$sxml = simplexml_import_dom($dom_xml);
Next we need our TextFrame elements; we could either step through the structure explicitly, as you had before:
$textFrames = $sxml->Spread->TextFrame;
Or we could use XPath to search for matching tag names within our current node (. is the current element, and // means "any descendant":
$textFrames = $sxml->xpath('.//TextFrame');
The first will give you a SimpleXMLElement object, and the second an array, but either way, you can use foreach to go through the matches.
This time we definitely want an XPath expression to get the PathPointType nodes, to avoid all the nested loops through levels we're not that interested in:
foreach ( $textFrames as $frame ) {
$pathPointTypes = $frame->xpath('.//PathPointType');
foreach ( $pathPointTypes as $type ) {
echo $type['Anchor'] . PHP_EOL;
}
}
Note that you don't need to call $type->attributes(); unless you're dealing with namespaces, all you need to get an attribute is $node['AttributeName']. Beware that attributes in SimpleXML are objects though, so you'll often want to force them to be strings with (string)$node['AttributeName'].
To take the final example, you might then have something like this:
$frames = [];
foreach ( $sxml->Spread->TextFrame as $frame ) {
$anchors = [];
$pathPointTypes = $frame->xpath('.//PathPointType');
foreach ( $pathPointTypes as $type ) {
$anchors[] = ['Anchor' => (string)$type['Anchor']];
}
$frames[] = $anchors;
}
When attempting to use SimpleXML's addChild() method towards the end of the code block below and printing the feed, the output is not the required result. When tested with a string value, addChild() correctly outputs both the name of the node and the value, however I'm not sure if the array or the object inside it are actually within the scope of the first foreach loop.
I want to access the 'name' and 'type' properties of the $nameType object and output them to my main feed with addChild().
//Turns base feed into SimpleXML object.
$feed = simplexml_load_string($xml);
foreach($feed->property as $property) {
//Gets latitude and longitude from each property.
$latitude = $property->latitude;
$longitude = $property->longitude;
//Adds latitude and longitude values into Google Places API URL.
$googleURL = 'https://maps.googleapis.com/maps/api/place/nearbysearch/xml?location='.$latitude.','.$longitude.'&radius=1000&types=train_station&key=my-google-key';
//Gets XML from Google Places and parses into SimpleXML Object.
$googleXMLfile = file_get_contents($googleURL);
$googleXMLdata = simplexml_load_string($googleXMLfile);
//Array for limiting number of results.
$googleStoredXMLDataArray = array();
foreach ($googleXMLdata->result as $result) {
//Assigns result 'name' and 'type' to variables.
$name = $result->name;
$type = $result->type;
//Creates object to store name and type together.
$nameType = new StdClass();
$nameType->name = $name;
$nameType->type = $type;
//Pushes object to array and outputs results limiting feed to 3 results.
array_push($googleStoredXMLDataArray, $nameType);
$output = array_slice($googleStoredXMLDataArray, 0, 3);
}
//Adding proximityTo destination to property nodes in the feed parser.
//Error - needs to pull properties from object inside the array.
$property->addChild('proximityTo_name', '$googleStoredXMLDataArray->$nameType->name');
$property->addChild('proximityTo_type', '$googleStoredXMLDataArray->$nameType->type');
}
print_r($feed);
Do not forget, $googleStoredXMLDataArrayis an indexed array of stdClass objects. Getting the value of these objects in the array is done with an index like this:
$googleStoredXMLDataArray[$index]->name;
$googleStoredXMLDataArray[$index]->type;
where $index is between 0 and count($googleStoredXMLDataArray)-1. I believe 0 is the most accurate hit and the last value the most inaccurate. To get the last value (most inaccurate), use this:
$i = count( $googleStoredXMLDataArray ) - 1;
$property->addChild('proximityTo_name', $googleStoredXMLDataArray[$i]->name);
$property->addChild('proximityTo_type', $googleStoredXMLDataArray[$i]->type);
Rewrite the last part should do the trick of adding ALL proximity values:
foreach( $googleStoredXMLDataArray as $prox ) {
$property->addChild('proximityTo_name', $prox->name);
$property->addChild('proximityTo_type', $prox->type);
}
If you want to skip the XML parsing, and just parse an array of data you can always use JSON instead:
$googleURL = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
. '?location='.$latitude.',' . $longitude
. '&radius=1000&types=train_station&key=my-google-key';
$googleObject = json_decode( file_get_contents($googleURL), true );
I have the following JSON structure
{"Id":"1","Persons":[{"Name":"Carl","Time":"00:00:03","info":"","Timeext":"","Timeout":"","Timein":""}, {"Name":"Carl","Time":"00:00:03","info":"","Timeext":"","Timeout":"","Timein":""}{"Name":"Luis","Time":"00:00:08","info":"","Timeext":"","Timeout":"","Timein":""}]}
How I can have acces or read the item inside the nest? For example if I just want the value of time for Carl or all information about Carl. Till now I just can get without a problem the single item in the collection 'Id'. The rst nested items not.
I tryed with json_decode like this:
if( $_POST ) {
$arr['Id'] = $_POST['Id'];
$arr['NP'] = $_POST['NP'];
$jsdecode = json_decode($arr);
foreach ($jsdecode as $values){
echo $values->Time;
}
Can PLEASE somebody help me?
if( $_POST ) {
$arr['Id'] = $_POST['Id'];
$arr['NP'] = $_POST['NP'];
$jsdecode = json_decode($arr,true);
foreach ($jsdecode as $values){
echo $values->Time;
}
Adding 'true' to json_decode converts it to array
You are processing it correct , Just add true as the second parameter to json_decode which will be converted to an Array like
$jsdecode = json_decode($arr,true);
I have a foreach like :
foreach($values as $key => $value){
$name = $value['name'];
if(!isset($array[$value['position']])){
$array[$value['position']] = new \stdClass();
}
$array[$value['position']]->$name = $value['value'];
}
So in my loop, in $value, I have $name, $position and $value.
$name is the name of the property
$value is the value
$position is the position of the object in the array (index)
In this loop, i check first in my object is already created in the specific index (position), if not i create it, and after i put the value in the correct property.
My problem is, if in my array of value i don't have all the positions following (0,1,2,3) but for example (0,1,3,4), my script bug and i don't have the correct array at the end.
How can i detect if i miss an index ? And how can i fix this ?
Thanks for help !
PS : I don't know if you have enough informations.. tell me !
EDIT :
At the end, the correct output must be :
[Object { name="d", complet="false"}, Object { adresse="d", complet="false"}]
But, if the script bug with the index, i have :
Object { 0={...}, 1={...}, 2={...}, plus...}
my question has to do with PHP and XML. I would like to echo out some attributes, but echo ones that repeat only once.
Say this was the XML I was dealing with, and it was called beatles.xml:
<XML_DATA item=“TheBeatles”>
<Beatles>
<Beatle Firstname=“George” Lastname=“Harrison” Instrument=“Guitar”>Harrison, George</Beatle>
<Beatle Firstname=“John” Lastname=“Lennon” Instrument=“Guitar”>Lennon, John</Beatle>
<Beatle Firstname=“Paul” Lastname=“McCartney” Instrument=“Bass”>McCartney, Paul</Beatle>
<Beatle Firstname=“Ringo” Lastname=“Starr” Instrument=“Drums”>Starr, Ringo</Beatle>
</Beatles>
</XML_DATA>
This is the PHP I have so far:
$xml = simplexml_load_file("http://www.example.com/beatles.xml");
$beatles = $xml->Beatles->Beatle;
foreach($beatles as $beatle) {
echo $beatle->attributes()->Instrument.',';
}
I would expect this to echo out Guitar,Guitar,Bass,Drums, but I would like Guitar to only display once. How would I prevent repeat attribute values from echoing out?
Inside the foreach loop, cast the instrument name as a string and push it into an array. Once the loop finishes execution, you will have an array containing all the instrument names (with duplicates, of course). You can now use array_unique() to filter out the duplicate values from the array:
$instruments = array();
foreach($beatles as $beatle) {
$instruments[] = (string) $beatle->attributes()->Instrument;
}
$instruments = array_unique($instruments);
Demo.
$xml = simplexml_load_file("http://www.example.com/beatles.xml");
$beatles = $xml->Beatles->Beatle;
$result = array();
foreach($beatles as $beatle) {
if (!array_key_exists($beatle->attributes()->Instrument, $result)) {
$result[] = $beatle->attributes()->Instrument;
// echo $beatle->attributes()->Instrument.',';
}
}
then Loop through the $result array with foreach
Either use xpath.