xPath retrieve onclick value - php

I'm trying to retrieve the onclick value on a td element. This is what I have so far.
$xpath = new DOMXPath($dom);
$trs = $xpath->query("/html/body//table/tr");
foreach ($trs as $tr){
$tds = $xpath->query("td", $tr);
foreach ($tds as $td) {
$a = $xpath->query("#onclick", $td);
echo $a->nodeValue;
echo $td->nodeValue;
}
}
This doesn't seem to be working though.
Here's the structure
<table>
<tr>
<td>Name</td>
<td onclick="blahblah">Author</td>
<td>Title</td>
</tr>
</table>

$a is a NodeList, you must select an item:
#print($a->item(0)->nodeValue);

Related

I have to display image and data from xml, how can I do it in php?

Each time it loops, the text that it shows only the Product_URL. I really confuse how to solve this problem. I guess there is something wrong with the loop.
<html>
<head>
<title>Display main Image</title>
</head>
<body>
<table>
<tr>
<th>Thumbnail Image</th>
<th>Product Name</th>
<th>Product Description</th>
<th>Price</th>
<th>Weight</th>
<th>Avail</th>
<th>Product URL</th>
</tr>
<tr>
<?php
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->Load('xml_feeds7.xml');
$xpath = new DOMXPath($doc);
$listquery = array('//item/thumbnail_url', '//item/productname', '//item/productdesciption', '//item/price', '//item/weight', '//item/avail', '//item/product_url');
foreach ($listquery as $queries) {
$entries = $xpath->query($queries);
foreach ($entries as $entry) { ?>
<tr>
<td>
<img src="<?php echo $entry->nodeValue; ?>" width="100px" height="100px">
</td>
<td>
<?php echo "$entry->nodeValue"; ?>
</td>
<td>
<?php echo "$entry->nodeValue"; ?>
</td>
<td>
<?php
$price_value = $entry->nodeValue;
echo str_replace($price_value, ".00", "");
?>
</td>
<td>
<?php
$weight_value = $entry->nodeValue;
echo str_replace($weight_value, ".00", "");
?>
</td>
<td>
<?php echo "$entry->nodeValue"; ?>
</td>
<td>
<?php echo "$entry->nodeValue"; ?>
</td>
<td>
<?php echo "$entry->nodeValue"; ?>
</td>
</tr>
}
}
</tr>
</table>
</body>
</html>
The table should be displaying:
---------------------------------------------------------------------------------
| Thumbnail | Product Name | Description | Price | Weight | Avail | Product_URL |
---------------------------------------------------------------------------------
Xpath can return scalar values (strings and numbers) directly, but you have to do the typecast in the Expression and use DOMxpath::evaluate().
You should iterate the items and then use the item as a context for the detail data expressions. Building separate lists can result in invalid data (if an element in on of the items is missing).
Last you can use DOM methods to create the HTML table. That way it will take care of escaping and closing the tags.
$xml = <<<'XML'
<items>
<item>
<thumbnail_url>image.png</thumbnail_url>
<productname>A name</productname>
<productdescription>Some text</productdescription>
<price currency="USD">42.21</price>
<weight unit="g">23</weight>
<avail>10</avail>
<product_url>page.html</product_url>
</item>
</items>
XML;
$document = new DOMDocument;
$document->preserveWhiteSpace = false;
$document->loadXml($xml);
$xpath = new DOMXPath($document);
$fields = [
'Thumbnail' => 'string(thumbnail_url)',
'Product Name' => 'string(productname)',
'Description' => 'string(productdescription)',
'Price' => 'number(price)',
'Weight' => 'number(weight)',
'Availability' => 'string(avail)',
'Product_URL' => 'string(product_url)'
];
$html = new DOMDocument();
$table = $html->appendChild($html->createElement('table'));
$row = $table->appendChild($html->createElement('tr'));
// add table header cells
foreach ($fields as $caption => $expression) {
$row
->appendChild($html->createElement('th'))
->appendChild($html->createTextNode($caption));
}
// iterate the items in the XML
foreach ($xpath->evaluate('//item') as $item) {
// add a new table row
$row = $table->appendChild($html->createElement('tr'));
// iterate the field definitions
foreach ($fields as $caption => $expression) {
// fetch the value using the expression in the item context
$value = $xpath->evaluate($expression, $item);
switch ($caption) {
case 'Thumbnail':
// special handling for the thumbnail field
$image = $row
->appendChild($html->createElement('td'))
->appendChild($html->createElement('img'));
$image->setAttribute('src', $value);
break;
case 'Price':
case 'Weight':
// number format for price and weight values
$row
->appendChild($html->createElement('td'))
->appendChild(
$html->createTextNode(
number_format($value, 2, '.')
)
);
break;
default:
$row
->appendChild($html->createElement('td'))
->appendChild($html->createTextNode($value));
}
}
}
$html->formatOutput = TRUE;
echo $html->saveHtml();
Output:
<table>
<tr>
<th>Thumbnail</th>
<th>Product Name</th>
<th>Description</th>
<th>Price</th>
<th>Weight</th>
<th>Availability</th>
<th>Product_URL</th>
</tr>
<tr>
<td><img src="image.png"></td>
<td>A name</td>
<td>Some text</td>
<td>42.21</td>
<td>23.00</td>
<td>10</td>
<td>page.html</td>
</tr>
</table>
I've changed it to use SimpleXML as this is a fairly simple data structure - but this fetches each <item> and then displays the values from there. I've only done this with a few values, but hopefully this shows the idea...
$doc = simplexml_load_file('xml_feeds7.xml');
foreach ( $doc->xpath("//item") as $item ) {
echo "<tr>";
echo "<td><img src=\"{$item->thumbnail_url}\" width=\"100px\" height=\"100px\"></td>";
echo "<td>{$item->productname}</td>";
echo "<td>{$item->productdesciption}</td>";
// Other fields...
$price_value = str_replace(".00", "",(string)$item->price);
echo "<td>{$price_value}</td>";
// Other fields...
echo "</tr>";
}
Rather than use XPath for each value, it uses $item->elementName, so $item->productname is the productname. A much simpler way of referring to each field.
Note that with the price field, as you are processing it further - you have to cast it to a string to ensure it will process correctly.
Update:
If you need to access data in a namespace in SimpleXML, you can use XPath, or in this case there is a simple (bit roundabout way). Using the ->children() method you can pass the namespace of the elements you want, this will then give you a new SimpleXMLElement with all the elements for that namespace.
$extraData = $item->children('g',true);
echo "<td>{$extraData->productname}</td>";
Now - $extraData will have any element with g as the namespace prefix, and they can be referred to in the same way as before, but instead of $item you use $extraData.

DOMDocument How get element a from node?

$url = file_get_contents('test.html');
$DOM = new DOMDocument();
$DOM->loadHTML(mb_convert_encoding($url, 'HTML-ENTITIES', 'UTF-8'));
$trs = $DOM->getElementsByTagName('tr');
foreach ($trs as $tr) {
foreach ($tr->childNodes as $td){
echo ' ' .$td->nodeValue;
}
}
test.html
<html>
<body>
<table>
<tbody>
<tr>
<td style="background-color: #FFFF80;">1</td>
<td>test1</td>
</tr>
<tr>
<td style="background-color: #FFFF80;">2</td>
<td>test2</td>
</tr>
<tr>
<td style="background-color: #FFFF80;">3</td>
<td>test3</td>
</tr>
</tbody>
</table>
</body>
</html>
in result i get:
1 test1 2 test2 3 test3
But how get link from td a?
And how get html from td?
P.S.: i try with $td->find('a'); and $td->getElementsByTagName('a'); but it not work...
I improved your code a little bit and this version works fine for me:
$DOM = new DOMDocument();
$DOM->loadHTML(mb_convert_encoding($url, 'HTML-ENTITIES', 'UTF-8'));
$trs = $DOM->getElementsByTagName('tr');
foreach ($trs as $tr) {
foreach ($tr->childNodes as $td){
if ($td->hasChildNodes()) { //check if <td> has childnodes
foreach($td->childNodes as $i) {
if ($i->hasAttributes()){ //check if childnode has attributes
echo $i->getAttribute("href") . "\n"; // get href="" attribute
}
}
}
}
}
Result:
test1.php
test2.php
test3.php

PHP textContent removing HTML?

I have the following script which loops through a HTML table and gets the values from it then returns the value of the table in a td.
$tds = $dom->getElementsByTagName('td');
// New dom
$dom2 = new DOMDocument;
$x = 1;
// Loop through all the tds printing the value with a new class
foreach($tds as $t) {
if($x%2 == 1)
print "</tr><tr>";
$class = ($x%2 == 1) ? "odd" : "even";
var_dump($t->textContent);
print "<td class='$class'>".$t->textContent."</td>";
$x++;
}
But the textContent seems to be stripping the HTML tags (for example it is a <p></p> wrapper tag). How can I get it to just give me the value?
Or is there another way of doing this? I have the following html
<table>
<tr>
<td>q1</td>
<td>a1</td>
</tr>
<tr>
<td>q2</td>
<td>a2</td>
</tr>
</table>
and I need to make it look like
<table>
<tr>
<td class="odd">q1</td>
<td class="even">a1</td>
</tr>
<tr>
<td class="odd">q2</td>
<td class="even">a2</td>
</tr>
</table>
It will always look the exact same way (minus extra element rows and the values which change).
Any help?
According to MDN this is the expected behaviour of textContent.
You can just add the class to the tds in the DomDocument
$tds = $dom->getElementsByTagName('td');
$x = 1;
foreach($tds as $td) {
if($x%2 == 1){
$td->setAttribute('class', 'odd');
}
else{
$td->setAttribute('class', 'even');
}
$x++;
}

PHP DOM accessing the object with same attribute

I want to get the date object text content and Team 1. But Team 2 object has the same attribute option with date object. How can I get the right content? If I echo $date I get date value with Team2... How should I write conditions?
<table width="100%" cellpadding=2 cellspacing=0 id="tblFixture" border=0>
<tr class=row1 align=center side='home'>
<td align=left>21.09.1928</td>
<td> </td>
<td align='right'><span class='team'>Team 1</span></td>
<td align=left><a href='http://www.foo.com/bar' target='_blank'>Team 2</a></td>
</td>
</tr>
PHP Code:
$url = "http://www.bla.com/bla.html";
$dom = new DOMDocument;
#$dom->loadHTMLFile($url);
$xpath = new DOMXPath($dom);
$nlig = $xpath->query('//table[#id="tblFixture"]/tr[#side=\'home\']');
$i = 0;
foreach ($nlig AS $val)
{
$date = $xpath->query('//table[#id="tblFixture"]/tr[#side=\'home\'][#class=\'row1\']/td[#align=\'left\']')->item($i)->textContent;
$first_team = $xpath->query('//table[#id="tblFixture"]/tr[#side=\'home\']/td[#align=\'right\']/span[#class=\'team\']')->item($i)->textContent;
echo $date, $first_team, "<br />";
$i++;
}
You can use a regular expression to validate / find the date.
Something like:
preg_match("/<td align=left>([0-9]{2}.[0-9]{2}.[0-9]{4})<\/td>/", $html, $matches);

Alternating row colors in html table from xml datasource with php

I would like to alternate the row color from odd and even from the following xml with php.
<?php
// load SimpleXML
$books = new SimpleXMLElement('books.xml', null, true);
echo <<<EOF
<table>
<tr>
<th>Title</th>
<th>Author</th>
<th>Publisher</th>
<th>Price at Amazon.com</th>
<th>ISBN</th>
</tr>
EOF;
foreach($books as $book) // loop through our books
{
echo <<<EOF
<tr>
<td>{$book->title}</td>
<td>{$book->author}</td>
<td>{$book->publisher}</td>
<td>\${$book->amazon_price}</td>
<td>{$book['isbn']}</td>
</tr>
EOF;
}
echo '</table>';
?>
How would I do this with php considering my source is XML?
Add a counter, initialize it to zero, increment on each iteration and put different classes in tr depending on the value of $counter%2 (zero or not). (like ($counter%2)?'odd':'even').
Something like this:
for($i=0;$i<6;$i++)
{
if($i % 2)
{
// even
}else{
// odd
}
}
Here's a simple way.
<?php
// load SimpleXML
$books = new SimpleXMLElement('books.xml', null, true);
echo <<<EOF
<table>
<tr>
<th>Title</th>
<th>Author</th>
<th>Publisher</th>
<th>Price at Amazon.com</th>
<th>ISBN</th>
</tr>
EOF;
$even = true;
foreach($books as $book) // loop through our books
{
$class = $even ? 'even' : 'odd';
$even = $even ? false : true;
echo <<<EOF
<tr class="$class">
<td>{$book->title}</td>
<td>{$book->author}</td>
<td>{$book->publisher}</td>
<td>\${$book->amazon_price}</td>
<td>{$book['isbn']}</td>
</tr>
EOF;
}
echo '</table>';
?>

Categories