getting value of custom attributes using XPATH and PHP - php

I am trying to extract the data stored in a list. The troubling piece is the "custom-data" entity.
<li id="myid" custom-data="123456789" class="search-query">
...lots of child elements
I get all the string data with querying DomXPath object for "search-query" and than extract it with this the code below.
$id = $exampleXPath->query("//li[#class='search-query']");
foreach ($id as $element) {
$nodes = $element->childNodes;
foreach ($nodes as $node) {
echo "$node->nodeValue<br>";
}
}
I would like to also get the value of "custom-data" of each "search-query" object, but I don't how to get it. Any ideas?

You already have reference to all "search-query" elements, so getting the attribute should be as straightforward as calling getAttribute("attribute_name") on each element:
$custom_data = $element->getAttribute("custom-data");

Related

get elements by name from a DOMNodeList

In the following code, I retrieve with DOM a list of nodes from an xml document. Then I would like to select, by their tag name, some of these nodes.
$index = new DOMDocument();
$index->load('index.xml');
$xpath = new DOMXpath($index);
$related_notions = $xpath->query("/index/notion[name='" . $name . "']/relations/*"); // the variable $name is dynamically defined previously in the script
foreach ($related_notions->getElementsByTagName("superordinate") as $item) {
// do something
}
I get the following error: Uncaught Error: Call to undefined method DOMNodeList::getElementsByTagName()
I don't understand why the method getElementsByTagName() is not defined for DOMNodeList. After all, getting elements by their name seems to me something obvious that one might want to do with a node list. At any rate, my actual question is: How can I do what I want to do? That is, in the absence of the method getElementsByTagName(), how do I get elements by tag name from a node list?
Thanks in advance for your help!
I found a solution to my problem, namely to test for the nodeName with an if statement inside the foreach:
$index = new DOMDocument();
$index->load('index.xml');
$xpath = new DOMXpath($index);
$related_notions = $xpath->query("/index/notion[name='" . $name . "']/relations/*");
foreach ($related_notions as $item) {
if ($item->nodeName == "superordinate") {
// do something
}
}

Xpath that checks element does not contain a specific src attribute in PHP

Trying to find element without a specific img src, but is grabbing all elements in variable not the ones I want, also causing the loop to loop indefinitly
$books = '<div> stuff heer < img src ="/assets/images/post/books.svg"/ ></div>';
$books2 = array();
foreach($books as $v)
{
$dom = new DOMDocument;
#$dom->loadHTML($v);
$xpath = new DomXpath($dom);
$div = $xpath->query('//*[not(contains(src,"/assets/images/post/books.svg"))]');
foreach ($div as $a) {
if(!empty($a))
{
$books2[] = $v;
}
}
} var_dump($books2); //problem is that this dumps all elements from initial books array and also oddly loops indefinitely..
however, if I try the code below it works perfectly and outputs correct.. any ideas why above doesnt work?
$books2 = array();
foreach($books as $v)
{
$dom = new DOMDocument;
#$dom->loadHTML($v);
$xpath = new DomXpath($dom);
$div = $xpath->query('//*[#src="/assets/images/post/books.svg"]');
foreach ($div as $a) {
if(!empty($a))
{
$books2[] = $v;
}
}
} var_dump($books2);
There are a issues with the code; the first being that src and #src are two different things, the former being an element and the latter an attribute.
Secondly, the query is not restricted enough; it queries all nodes that do not have a src attribute, whereas you're only interested in finding images, i.e.:
//img[not(contains(#src,"/assets/images/post/books.svg"))]
Lastly, from your question it seems that you're interested in knowing whether there is at least one such element present, in which case you don't have to do any inner loops:
$n = $xpath->query('//img[not(contains(#src,"/assets/images/post/books.svg"))]')->length;
if ($n) {
$books2[] = $v;
}
In the first code block, you are missing # when referencing the src attribute.
This makes the expression select all of elements that do not contain a src element containing "/assets/images/post/books.svg" (which is all elements in the document), instead of selecting the elements that have a src attribute who's value does not contain that string.
However, that will still select most of the elements in the document.
You want to select all of the elements that have a #src and ensure that the #src attribute's value does not contain that path:
//*[#src[not(contains(.,"/assets/images/post/books.svg"))]]

QueryPath find elements with namespaced attributes

I'm not finding a way to retrieve all elements that have an attribute ec:edit. I've only found examples getting namespaced elements, but not attributes.
And there is also no result when searching the attributes with attr() or hasAttr().
dbpedia example:
foreach ($qp->branch()->find('foaf|page') as $img) {
print $img->attr('rdf:resource') . PHP_EOL;
}
rdf file sample:
<dbpprop:artist rdf:resource="http://dbpedia.org/resource/The_Beatles" />
But this won't retrieve any results:
$edits = $htmldocument->find('div[mc|edit];
foreach ($edits as $key => $value) {
echo $value->attr('mc:edit');
}
sample data:
<div mc:edit="stuff"> // etc
I get nothing.
Ok, lambdas solve everything:
find('div')->filterLambda('return qp($item)->hasAttr("mc:edit");');

PHP: How to convert array to XML with support to attributes (DOMi ?)

I'm using DOMi ( http://domi.sourceforge.net ) to create XML from arrays.
But I don't know how to create attributes in these XML (in arrays, so these attributes appear in the XML). How can I construct these arrays so I can get some tags with attributes after the convertion?
Thank you!
Looking at the source code, apparently you pass the second argument "attributes" to attachToXml:
public function attachToXml($data, $prefix, &$parentNode = false) {
if(!$parentNode) {
$parentNode = &$this->mainNode;
}
// i don't like how this is done, but i can't see an easy alternative
// that is clean. if the prefix is attributes, instead of creating
// a node, just put all of the data onto the parent node as attributes
if(strtolower($prefix) == 'attributes') {
// set all of the attributes onto the node
foreach($data as $key=>$val)
$parentNode->setAttribute($key, $val);
$node = &$parentNode;
}
//...
}

Choosing Last Node in SimpleXML

I want to find the attribute of the last node in the xml file.
the following code find's the attribute of the first node. Is there a way to find the last node ?
foreach ($xml->gig[0]->attributes() as $Id){
}
thanks
I'm not to familiar with PHP but you could try the following, using an XPath query:
foreach ($xml->xpath("//gig[last()]")[0]->attributes() as $Id){
}
To get to the last gig node, as Frank Bollack noted, we could use XPath.
foreach (current($xml->xpath('/*/gig[last()]'))->attributes() as $attr) {
}
Or a little more verbose but nicer:
$attrs = array();
$nodes = $xml->xpath('/*/gig[last()]');
if (is_array($nodes) && ! empty($nodes)) {
foreach ($nodes[0]->attributes() as $attr) {
$attrs[$attr->getName()] = (string) $attr;
}
}
var_dump($attrs);
It's true that you could use XPath to get the last node (be it a <gig/> node or otherwise) but you can also mirror the same technique you used for the first node. This way:
// first <gig/>
$xml->gig[0]
// last <gig/>
$xml->gig[count($xml->gig) - 1]
Edit: I've just realized, are you simply trying to get the #id attribute of the first and the last <gig/> node? In which case, forget about attributes() and use SimpleXML's notation instead: attributes are accessed as if they were array keys.
$first_id = $xml->gig[0]['id'];
$last_id = $xml->gig[count($xml->gig) - 1]['id'];
I think that this xpath expression should work
$xml->xpath('root/child[last()]');
That should retrieve the last child element that is a child of the root element.

Categories