This code, returned hrefs to content, now I want to extract content form this hrefs and sent it to my view. Name divs which I need to extract:
<div class="c_pad">
<div class="c_label">
<span class="std_header2">Contact:</span>
</div>
<div class="c_name">
<span class="std_text_b">Monkey</span>
</div>
<div class="clear"></div>
</div>
<div class="c_pad">
<div class="c_label">
<span class="std_header2">Phone number:</span>
</div>
<div class="c_phone">
<span class="std_text_b">001111111</span>
</div>
<div class="clear"></div>
</div>
for($i=0; $i <= 1; $i++)
{
$p = new Client();
$d = $p->request('GET', ''.$link.'&std=1&results='. $i);
$n = $d->filter('a[class="o_title"]')->each(function ($node)
{
$pp = new Client();
$dd = $pp->request('GET', $node->attr('href'));
$kk = $dd->filter('div[id="adv_desc"]')->each(function ($tekst) { echo $node->attr('href').'<br>'.$tekst->text();
});
});
}
You want to filter specific tags with attributes.
But you are using $d->filter('a[class="o_title"]').
This filters the tag a with the attribute class="o_title". And that's not part of your content.
You simply need to adjust your node filter to select the correct elements.
Use the jQuery Selectors Syntax: https://api.jquery.com/category/selectors/
Referencing the documentation of Symfony's DomCrawler, which is used by Goutte:
http://symfony.com/doc/current/components/dom_crawler.html#node-filtering
Related
I inherited the following piece of PHP code, that removes elements from the DOM before pushing the content into a page. We only want to show the first 5 elements to not have a too long page
Assuming the code retrieves an HTML fragment structured like this:
<div class='year'>2019</div>
<div class='record'>Record A</div>
<div class='record'>Record B</div>
<div class='year'>2018</div>
<div class='record'>Record C</div>
<div class='record'>Record D</div>
<div class='record'>Record E</div>
<div class='year'>2017</div>
<div class='record'>Record F</div>
<div class='year'>2016</div>
<div class='record'>Record G</div>
Now, the below piece of code removes all the extra records:
$dom = new DOMDocument();
// be sure to load the encoding
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $tmp);
// let's use XPath
$finder = new DomXPath($dom);
// set the limit
$limit = 5; $cnt = 0;
// and remove unwanted elements
foreach($finder->query("//*[contains(#class, 'record')]") as $elm ) {
if ($cnt >= $limit)
$elm->parentNode->removeChild($elm);
$cnt++;
}
// finally, echo
echo $dom->saveHTML($dom->documentElement);
Logically, I end up having the following HTML:
<div class='year'>2019</div>
<div class='record'>Record A</div>
<div class='record'>Record B</div>
<div class='year'>2018</div>
<div class='record'>Record C</div>
<div class='record'>Record D</div>
<div class='record'>Record E</div>
<div class='year'>2017</div>
<div class='year'>2016</div>
How could I identify all the elements having the class year and having the next sibling also having this class and delete it? (here that would get the 2017 element)
Then I believe it would only be a matter of checking if the last element has the class year and remove it.
Or is there a cleaner way to achieve that?
You can add an extra foreach after the current one...
foreach($finder->query("//div[#class='year']/following-sibling::div[1][#class='year']")
as $elm ) {
$elm->parentNode->removeChild($elm);
}
The XPath here is looking for a <div class="year"> element and then only looking at the next <div> tag for the same thing (following-sibling::div[1] limits it to just the next div tag after the current one).
Here is a plain JS method in case you want to do this on the client instead
const recs = document.querySelectorAll(".record");
const divs = document.querySelectorAll("div");
const lastRec = recs[4];
let found = false;
divs.forEach(div => {
div.classList.toggle("hide",found)
if (div === lastRec) found = true
})
.hide { display:none}
<div class='year'>2019</div>
<div class='record'>Record A</div>
<div class='record'>Record B</div>
<div class='year'>2018</div>
<div class='record'>Record C</div>
<div class='record'>Record D</div>
<div class='record'>Record E</div>
<div class='year'>2017</div>
<div class='record'>Record F</div>
<div class='year'>2016</div>
<div class='record'>Record G</div>
I finally ended up using the following code:
$dom = new DOMDocument();
// be sure to load the encoding
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $tmp);
// let's use XPath
$finder = new DomXPath($dom);
foreach($finder->query("(//*[contains(#class, 'record')])[5]/following-sibling::*") as $elm) {
$elm->parentNode->removeChild($elm);
}
// finally, echo
echo $dom->saveHTML($dom->documentElement);
it allowed me to achieve my goal in 1 pass without using nested loops
I have html page what im trying to read(used htmlsql.class.php, but as its too old and outdated, then i have to use phpQuery).
The html markup is:
<ul class="small-block-grid-1 medium-block-grid-2 large-block-grid-3">
<li>
<div data-widget-type="epg.tvGuide.channel" data-view="epg.tvGuide.channel" id="widget-765574917197" class=" widget-epg_tvGuide_channel">
<div class="group-box">
<div class="group-header l-center" data-action="togglePreviousBroadcasts">
<span class="header-text">
<img src="logo.png" style="height: 40px" />
</span>
</div>
<div>
<div class="tvGuide-item is-past">
<span data-action="toggleEventMeta">
06:15 what a day
</span>
<div class="tvGuide-item-meta">
Some text.
<div>Näita rohkem</div>
</div>
</div>
<div class="tvGuide-item is-current">
<span data-action="toggleEventMeta">
06:15 what a day
</span>
<div class="tvGuide-item-meta">
Some text.
<div>Näita rohkem</div>
</div>
</div>
<div class="tvGuide-item">
<span data-action="toggleEventMeta">
06:15 what a day
</span>
<div class="tvGuide-item-meta">
Some text.
<div>Näita rohkem</div>
</div>
</div>
</div>
</div>
Then with the previos thing it was fearly easy:
$wsql->select('li');
if (!$wsql->query('SELECT * FROM span')){
print "Query error: " . $wsql->error;
exit;
}
foreach($wsql->fetch_array() as $row){
But i could not read the class so i need to know when the class is current and when its not.
As im new to phpQuery then and reallife examples are hard to find.
can someone point me to the right direction.
I would like to have the "span" text and item meta, allso i like to know when the div class is "is-past" or "is-current"
You can find infos about phpQuery here: https://code.google.com/archive/p/phpquery/
I prefer "one-file" version on top in downloads:
https://code.google.com/archive/p/phpquery/downloads
Simple examples based on your code:
// for loading files use phpQuery::newDocumentFileHTML();
// for plain strings use phpQuery::newDocument();
$document = phpQuery::newDocumentFileHTML('http://domain.com/yourFile.html');
$items = pq($document)->find('.tvGuide-item');
foreach($items as $item) {
if(pq($item)->hasClass('is-past') === true) {
// matching past items
}
if(pq($item)->hasClass('is-current') === true) {
// matching current items
}
// examples for finding elements and grabbing text/attributes
$span = pq($item)->find('span');
$text_in_span = pq($span)->text();
$meta = pq($item)->find('.tvGuide-item-meta');
$link_in_meta = pq($meta)->find('a');
$href_of_link_in_meta = pq($link_in_meta)->attr('href');
}
I have an external file with lots of informations e.g
http://domain.com/thefile.html
Each Data in the file is wrapped into a <div> element:
....
<div class="lineData">
<div class="lineLData">Playstation</div>
<div class="lineRData">awesome</div>
</div>
<div class="lineData">
<div class="lineLData">xbox one</div>
<div class="lineRData">not awesome</div>
</div>
<div class="lineData">
<div class="lineLData">wii u</div>
<div class="lineRData">mhhhh</div>
</div>
....
Now I want to search the whole file for the Keyword "Playstation" and echo the whole <div>:
<div class="lineData">
<div class="lineLData">Playstation</div>
<div class="lineRData">awesome</div>
</div>
Is this possible with PHP ?
If we assume the resource / URL is $url :
$result = array();
$dom = new DOMDocument;
$dom->loadHTML(file_get_contents($url));
find all <div>'s with the class lineData using DomXPath :
$xpath = new DomXPath($dom);
$lineDatas = $xpath->query('//div[contains(#class,"lineData")]');
add all lineData <div>'s containing "playstation" to the $result array :
foreach($lineDatas as $lineData) {
if (strpos(strtolower($lineData->nodeValue), 'playstation') !== false) {
$result[] = $lineData;
}
}
example of outputting the result
foreach($result as $lineData) {
echo $dom->saveHTML($lineData);
}
outputs
<div class="lineData">
<div class="lineLData">Playstation</div>
<div class="lineRData">awesome</div>
</div>
when tested on the example HTML in OP.
Use DOMDocument for this purpose.
$dom = new DOMDocument;
$dom->loadHTMLFile("file.html");
Now you can search for the div:
$xpath = new DOMXPath($dom);
$res = $xpath->query("//*[contains(#class, 'lineData')]");
Now you have the div as DOMElement. Saving should be possible with these few lines:
$html = $res->ownerDocument->saveHTML($res);
I want to set the css TOP property different after every 3 div's
for eg:
<div style="top:100px;">
</div>
<div style="top:100px;">
</div>
<div style="top:100px;">
</div>
**Now after this the next 3 div's shall have**
<div style="top:150px;">
</div>
<div style="top:150px;">
</div>
<div style="top:150px;">
</div>
**Now after this the next 3 div's shall have**
<div style="top:200px;">
</div>
<div style="top:200px;">
</div>
<div style="top:200px;">
</div>
**and so on**
I want to do this dynamically using php.
Using the for loop i can check if
$ij=0; if($ij%3==0) {
echo "";
}
else {
}
But not sure how to get desired result.
Any help is really appreciated.
Try this:
$top = 50;
$n = 30; // no. of divs
for($i = 0; $i < $n; $i++) {
if($i % 3==0) $top+=50;
echo "<div style=\"top:".$top."px;\">\n</div>";
}
I have a $content with
<div class="slidesWrap">
<div class="slidesСontainer">
<div class="myclass">
...
</div>
<div class="myclass">
...
</div>
...
...
<div class="myclass">
...
</div>
</div>
<div class="nav">
...
</div>
</div>
some other text here, <p></p> bla-bla-bla
I would like to remove via PHP all the divs with class="myclass" except the first one, and add another div instead of others, so that the result is:
<div class="slidesWrap">
<div class="slidesСontainer">
<div class="myclass">
...
</div>
<div>Check all divs here</div>
</div>
<div class="nav">
...
</div>
</div>
some other text here, <p></p> bla-bla-bla
Would be grateful if someone can point me a solution.
UDATE2:
some similar question here
from that I came up with the following test code:
$content = '<div class="slidesWrap">
<div class="slidesСontainer">
<div class="myclass">
</div>
<div class="myclass">
</div>
<div class="myclass">
</div>
</div>
<div class="nav">
</div>
</div>
some other text here, <p></p> bla-bla-bla';
$dom = new DOMDocument();
$dom->loadHtml($content);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('//*[#class="myClass" and position()>1]') as $liNode) {
$liNode->parentNode->removeChild($liNode);
}
echo $dom->saveXml($dom->documentElement);
Any ideas where I can test it?
Here is what you are looking for (similar to your edit, but it removes the added html tags):
$doc = new DOMDocument();
$doc->loadHTML($content);
$xp = new DOMXpath($doc);
$elements = $xp->query("//div[#class='myclass']");
if($elements->length > 1)
{
$newElem = $doc->createElement("div");
$newElem->appendChild($doc->createTextNode("Check all divs "));
$newElemLink = $newElem->appendChild($doc->createElement("a"));
$newElemLink->setAttribute("href", "myurl");
$newElemLink->appendChild($doc->createTextNode("here"));
$elements->item(1)->parentNode->replaceChild($newElem, $elements->item(1));
for($i = $elements->length - 1; $i > 1 ; $i--)
{
$elements->item($i)->parentNode->removeChild($elements->item($i));
}
}
echo $doc->saveXML($doc->getElementsByTagName('div')->item(0));
$var = ':not(.myClass:eq(1))';
$var.removeClass("myClass");
$var.addClass("some_other_Class");
If I got you right, you've got a string called $content with all that content in it
It's not the best solution I guess but here is my attempt (which works fine for me):
if( substr_count($content, '<div class="myclass') > 1 ) {
$parts = explode('<div class="myclass',$content);
echo '<div class="myclass'.$parts[1];
echo '<div>Check all divs here</div>';
}
else {echo $content;}