so I have this xml
<xmlTag>
<item>etc etc</item>
<section>etc etc</section>
<item>etc etc</item>
<item>etc etc</item>
<section>etc etc</section>
<xmlTag>
and I want to process this in order, ie process the first item tag then the second section tag then the third item tag...etc
however when I use simplexml_load_string() the resultant object becomes
$xmlTag = {SimpleXMLElement}[2]
item = {array} [3]
section = {array} [2]
Hence it separates out the item tags and the section tags and now I have no way to determine the orderings between the item tags and the section tags....
Anyone know of an alternative way to figure out the order of the xml elements in this scenario?
Whatever dump function you're using there is misleading you (anything not dedicated to the purpose will, due to the large amount of "magic" supported by SimpleXML). The nodes have not been permanently separated out, it's just showing you that they can be accessed that way.
If you use the children() method, you will get them in the order they are defined in the document, regardless of tag name:
foreach ( $xmlTag->children() as $child_name => $child ) {
echo $child_name, "\n";
}
Note that children() doesn't actually return an array, just an "iterable" object. So unlike a real array, the same "key" can occur multiple times when you loop over it.
Related
I'm using SimpleXML to pull in a XML feed. I need to grab the second node with the same name.
Feed example is:
<parent-node>
<child-node>
<the-node>
<the-target>Text</target>
</the-node>
<the-node>
<the-target>Text</target>
</the-node>
</child-node>
</parent-node>
Since the nodes I am targeting use hyphens, I need to use bracket syntax
$item->{'parent-node'}->{'child-node'}->{'the-node'}
This will grab the first <the-node>
When using the bracket syntax, I cannot select the second <the-node>'s <the-target> using any of the following...
$item->{'parent-node'}->{'child-node'}->{'the-node[2]'}->{'the-target'}
$item->{'parent-node'}->{'child-node'}->{'the-node'[2]}->{'the-target'}
$item->{'parent-node'}->{'child-node'}->{'the-node'}[2]->{'the-target'}
My question is, how do I target childIndex while using the bracket syntax to grab the second <the-node>'s <target>?
--- UPDATES ---
After some of the answers, I have tried the following with no luck
$item->{'parent-node'}->{'child-node'}->{'the-node'}[1]->{'the-target'}
$item->{'parent-node'}->{'child-node'}->{'the-node'}->{'the-target'}[1]
$item->{'child-node'}->{'the-node'}->{'the-target'}[1]
SimpleXMLElement stores sibling nodes as if they were an array. This usually indicates that the values are stored with a 0-based index, ie. the first value in the array starts at index 0.
So in this case, the 2nd sibling node is only accessible using the index 1 instead of 2.
Also the root-level node does not have to be traversed into by default (unless you omitted some other XML or are using some non-default settings).
Try this:
// Will grab the 2nd <the-node/>
$node = $item->{'child-node'}->{'the-node'}[1];
Depending on if your initial code did work without the array access, you can try this too:
// Testing locally I was not able to use this and got an error
// But maybe things are omitted in your question.
$node = $item->{'parent-node'}->{'child-node'}->{'the-node'}[1];
The correct syntax looks like the following:
$item->{'child-node'}->{'the-node'}[0]; // First the-node
$item->{'child-node'}->{'the-node'}[1]; // Second the-node
If parent-node is the root element of all others, you cannot access it explicitly.
$item->{'parent-node'}->{'child-node'}->{'the-node'}[0];
The above code will result in error saying "Trying to get property of non-object".
Since parent-node is the top root element, you cannot access it explicitly.
Only the immediate child element of the top root element will be available to access in the SimpleXMLElement object.
I am working with migration and I am migrating taxonomy terms that the document has been tagged with. The terms are in the document are separated by commas. so far I have managed to separate each term and place it into an array like so:
public function prepareRow($row) {
$terms = explode(",", $row->np_tax_terms);
foreach ($terms as $key => $value) {
$terms[$key] = trim($value);
}
var_dump($terms);
exit;
}
This gives me the following result when I dump it in the terminal:
array(2) {
[0]=>
string(7) "Smoking"
[1]=>
string(23) "Not Smoking"
}
Now I have two fields field_one and field_two and I want to place the value 0 of the array into field_one and value 1 into field_two
e.g
field_one=[0]$terms;
I know this isn't correct and I'm not sure how to do this part. Any suggestions on how to do this please?
If you are only looking to store the string value of the taxonomy term into a different field of a node, then the following code should do the trick:
$node->field_one['und'][0]['value'] = $terms[0];
$node->field_two['und'][0]['value'] = $terms[1];
node_save($node);
Note you will need to load the node first, if you need help with that, comment here and will update my answer.
You are asking specifically about ArrayList and HashMap, but I think to fully understand what is going on you have to understand the Collections framework. So an ArrayList implements the List interface and a HashMap implements the Map interface.
List:
An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.
Map:
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
So as other answers have discussed, the list interface (ArrayList) is an ordered collection of objects that you access using an index, much like an array (well in the case of ArrayList, as the name suggests, it is just an array in the background, but a lot of the details of dealing with the array are handled for you). You would use an ArrayList when you want to keep things in sorted order (the order they are added, or indeed the position within the list that you specify when you add the object).
A Map on the other hand takes one object and uses that as a key (index) to another object (the value). So lets say you have objects which have unique IDs, and you know you are going to want to access these objects by ID at some point, the Map will make this very easy on you (and quicker/more efficient). The HashMap implementation uses the hash value of the key object to locate where it is stored, so there is no guarentee of the order of the values anymore.
You might like to try:
list($field_one, $field_two) = prepareRow($row);
The list function maps entries in an array (in order) to the variables passed by reference.
This is a little fragile, but should work so long as you know you'll have at least two items in your prepareRow result.
ok, this might be a stupid question, but how do I get one single element from an XML document?
I have this XML
$element = $response['linkedin'];
SimpleXMLElement Object
(
[id] => 575677478478
[first-name] => John
[last-name] => Doe
[email-address] => john#doe.com
[picture-url] => http://m3.licdn.com/mpr/mprx/123
[headline] => Headline goes here
[industry] => Internet
[num-connections] => 71
I just want to assign first-name as $firstName
I can loop over it using xPath, but that just seems like overkill.
ex:
$fName = $element->xpath('first-name');
foreach ($fName as $name)
{
$firstName = $name;
}
If you access a list of (one or more) element nodes in SimpleXML as a single element, it will return the first element. That is by default (and outlined as well in the SimpleXML Basic Usage):
$first = $element->{'first-name'};
If there are more than one element, you can specify which one you mean by using the zero-based index of it, either in square (array-access) or curly (property-access) brackets:
$first = $element->{'first-name'}[0];
$first = $element->{'first-name'}{0};
This also allows you to create a so called SimpleXML self-reference to access the element itself, e.g. to remove it:
unset($first[0]); # removes the element node from the document.
unset($first); # unsets the variable $first
You might think your Xpath would be overkill. But it's not that expensive in SimpleXML. Sometimes the only way to access an element is with Xpath even. Therefore it might be useful for you to know that you can easily access the first element as well per an xpath. For example the parent element in SimpleXML:
list($parent) $element->xpath('..'); # PHP < 5.4
$parent = $element->xpath('..')[0]; # PHP >= 5.4
As you can see it is worth to actually understand how things work to make more use of SimpleXML. If you already know all from the SimpleXML Basic Usage page, you might want to learn a bit more with the
SimpleXML Type Cheatsheet
How to tell apart SimpleXML objects representing element and attribute?
SimpleXMLElement implements JsonSerializable
Answer form per request. ^^
If that SimpleXMLElement is the only one contained within $resource['linkedin'], you can change it with:
$resource['linkedin']->{'first-name'} = $name;
That allows you direct access to the element without needing to do an xpath on it. ^^
You can use XPath to find the first instance of a matching element.
/root/firstname[1] would give you the first instance of firstname in your document.
$res=$response['linkedin']->xpath('/first-name[1]');
I have a bunch of dom manipulation functions within a class.
One of those functions assigns unique ids to specific nodes.
$resource_info_node->setAttribute('id', 'resource_'.$this->ids);
$details['id'] = 'resource_'.$this->ids;
$details['node'] = $resource_info_node;
$this->resource_nodes['resource_'.$this->ids] = $details;
$this->ids += 1;
later I want to look up and modify those nodes.
I have tried :
$current_node = $this->resource_nodes[$id]['node'];
When I print_r() I find that this node is a duplicate of the original node.
It has the original node's attributes but is not a part of the DOM tree.
I get the same results with :
$this->content->getElementById($id);
I suppose I based this whole thing on storing node references in an array. I thought that was a fine thing to do. Even if not, after that using getElementByID() should have returned the node within the dom.
I thought that, in PHP all objects were passed by reference. Including DOM nodes.
Any ideas on how I can test what is actually going on.
EDIT :
Well I used :
$this->xpath->query('//*[#id]');
That returned the right number of items with ids. The node is just not in the DOM tree when I edit it.
and
$current_node = &$this->resource_nodes[$id]['node'];
Using the reference syntax had no affect.
The strangest part is that get elementById() is not returning a node in the dom. It has all the right attributes except no parentNode.
FIX - not answer :
I just used xpath instead of my reference or getElementById().
Use reference explicity:
$current_node = &$this->resource_nodes[$id]['node'];
And modify $current_node
My Issue: Unable to append XML data to prexisting XML data in a MYSQL database.
I have an array - $buyer. Inside this array is a $key and $value similar to (shippingTotal => 55). What I want to do is use something similar to
$param = array(
'shippingTotal' => $shippingTotal
);
$where['quote_data = ?'] = $quoteNumber
$n = $db->update('quote_xml', simplexml_load_string($param), $where);
My hiccup is that the current data inside quote_data is an XML element containing LOTS of information. Is there any way to just "stick" shippingTotal into said existing XML? When I use the above code I just end up with quote_data becoming empty.
I also created a variable called $shippingTotal so that I wouldn't have to use $buyer['shippingTotal']. Still not functional.
Thank you for your time and assistance with this issue.
Aaron
I see a few issues with this:
First, simplexml_load_string doesn't accept array parameters, only XML strings. Since the $params is not a valid argument, it is returning boolean false. Even when successful, it returns a SimpleXMLElement. To convert that to an XML string, you would have to call the asXML() method on the returned object before passing it to Zend_Db_Table::update().
Second, most likely XML cannot just be "appended" to other XML. I don't know exactly what your table holds, but the XML needs to be programmatically added to the existing XML. You can't append XML because the data you want to add needs to be added to the proper nodes.
What you will have to do is first read the value of that column, parse it using SimpleXML, add your new data to the appropriate node in the document using one of the SimpleXML functions and then perform the update.
Hope that helps.