input xml file to php with multiple elements in a element? - php

Hello i am having much trouble inputting the following XML because of the multiple "authors" .. it works when i try with 1 but with multiple it fails. does anyone know how i can do the multiple author input? below is my an example of the xml and code
<pub>
<ID>3</ID>
<title>A Sampling Based Approach to Facial Feature Extraction</title>
<year>2005</year>
<booktitle>AutoID</booktitle>
<pages>51-56</pages>
<authors>
<author>john johnson</author>
<author>billy bob</author>
</authors>
</pub>
my code:
<?php
$pubs = new SimpleXMLElement('p.xml', null, true);
echo <<<EOF
<table>
<tr>
<th>ID</th>
<th>title</th>
<th>year</th>
<th>booktitle</th>
<th>pages</th>
<th>authors</th>
</tr>
EOF;
foreach($pubs as $pub)
{
echo <<<EOF
<tr>
<td>{$pub->ID}</td>
<td>{$pub->title}</td>
<td>{$pub->year}</td>
<td>{$pub->booktitle}</td>
<td>{$pub->pages}</td>
<td>{$pub->authors}</td>
</tr>
EOF;
}
echo '</table>';
?>

The authors are a several nodes, so you have to use a second loop. Additionally if you output values in HTML/XML, you need to escape them. htmlspecialchars() does a good enough job for that.
You're transforming XML into HTML here. XSLT would be a better tool for that. It is supported by the XSL extension in PHP.
In PHP you can use Xpath to extract data from XML:
$dom = new DOMDocument();
$dom->load('p.xml');
$xpath = new DOMXpath($dom);
echo <<<EOF
<table>
<tr>
<th>ID</th>
<th>title</th>
<th>year</th>
<th>booktitle</th>
<th>pages</th>
<th>authors</th>
</tr>
EOF;
$pubs = $xpath->evaluate('//pub');
foreach($pubs as $pub) {
echo '<tr>', "\n";
echo '<td>', htmlspecialchars($xpath->evaluate('string(./ID)', $pub)), '</td>', "\n";
echo '<td>', htmlspecialchars($xpath->evaluate('string(./title)', $pub)), '</td>', "\n";
echo '<td>', htmlspecialchars($xpath->evaluate('string(./year)', $pub)), '</td>', "\n";
echo '<td>', htmlspecialchars($xpath->evaluate('string(./booktitle)', $pub)), '</td>', "\n";
echo '<td>', htmlspecialchars($xpath->evaluate('string(./pages)', $pub)), '</td>', "\n";
// fetch all the authors into an array
$authors = array();
foreach ($xpath->evaluate('./authors/author', $pub) as $author) {
$authors[] = $author->nodeValue;
}
echo '<td>'.htmlspecialchars(implode(', ', $authors)).'</td>', "\n";
echo '</tr>', "\n";
}
echo '</table>';
The example uses DOMXpath::evaluate() because it allows to query string directly from the DOM. $xpath->evaluate('string(./ID)', $pub) returns the text content inside the ID child of the context node $pub, or an empty string if here is no child element ID.

The simpliest way, i think, is to convert it to json string than back to array and you will see that is an array so you will need another foreach
$pubs = new SimpleXMLElement('p.xml', null, true);
$jsonString = json_encode($pubs);
$assocArray = json_decode($jsonString, true);
echo '<pre>';
var_dump($assocArray);
echo '</pre>';
Sorry. I give you wrong informations, because if you tried this code you will get different result if you have more than 1 '' tags and if you have only 1.
So i have another solution:
<?php
$pubs = new SimpleXMLElement('test.xml', null, true);
echo <<<EOF
<table>
<tr>
<th>ID</th>
<th>title</th>
<th>year</th>
<th>booktitle</th>
<th>pages</th>
<th>authors</th>
</tr>
EOF;
$pubsXpath = $pubs->xpath('//pub');
/** #var SimpleXMLElement $pub */
foreach ($pubsXpath as $pub) {
$authorsSxml = $pub->xpath('authors/author');
$authors = join(', ', $authorsSxml);
echo <<<EOF
<tr>
<td>{$pub->ID}</td>
<td>{$pub->title}</td>
<td>{$pub->year}</td>
<td>{$pub->booktitle}</td>
<td>{$pub->pages}</td>
<td>{$authors}</td>
</tr>
EOF;
}
echo '</table>';
?>

Related

sorting PHP array by element in a foreach loop

I use PHP to access some data which is contained in a text file.
Here is a sample of the text file (myfile.txt) - each line has three fields separated by ||:
4e84||some text||category A
f17b||words words||category B
f7ac||some more text here||category B
8683||text text||category C
b010||more text||category A
fcc4||more text||category B
we47||more text||category C
08ml||more text||category A
This is the PHP code I use to show the contents of the txt file in a simple HTML table.
I access the file and I loop through each line to extract the three parts:
<?php
$lines = file("myfile.txt");
?>
<table>
<thead>
<tr>
<th>ID</th>
<th>TEXT</th>
<th>CATEGORY</th>
</tr>
</thead>
<tbody>
<?php
foreach ($lines as $line) {
list($id,$text,$category) = explode('||', $line);
echo '<tr>';
echo '<td>'.$id.'</td>';
echo '<td>'.$text.'</td>';
echo '<td>'.$category.'</td>';
echo '</tr>';
}
?>
</tbody>
</table>
I need to sort the lines according to the third field (category), so as to show the entries of category A, then B and then C.
I tried to use the sort() command within the foreach loop, with no success.
Any ideas?
You can use next approach:
$split_lines = [];
// first - split lines and put them into array
foreach ($lines as $line) {
$split_lines[] = explode('||', $line);
}
// sort array by function
usort($split_lines, fn($a,$b)=>$a[2]<=>$b[2]);
// show array as table
foreach ($split_lines as $line) {
echo '<tr>';
echo '<td>'.$line[0].'</td>';
echo '<td>'.$line[1].'</td>';
echo '<td>'.$line[2].'</td>';
echo '</tr>' . PHP_EOL;
}
run PHP online
You can achive it using two for loop only.
<?php
$lines = file("myfile.txt");
?>
<table>
<thead>
<tr>
<th>ID</th>
<th>TEXT</th>
<th>CATEGORY</th>
</tr>
</thead>
<tbody>
<?php
$listOfFiles = array();
foreach ($lines as $line) {
list($id,$text,$category) = explode('||', $line);
array_push($listOfFiles,$category."||".$text."||".$id);
}
sort($listOfFiles);
foreach($listOfFiles as $line)
{
list($category,$text,$id) = explode('||', $line);
echo '<tr>';
echo '<td>'.$id.'</td>';
echo '<td>'.$text.'</td>';
echo '<td>'.$category.'</td>';
echo '</tr>';
}
?>
</tbody>
</table>

Parsing content with Simple html dom from a table but with a condition

So I want to show in an 'echo' only the people that day which the situation is 'Yes', so let's assume today is only 'John' from my array list that have the situation 'Yes'.
$people = array('John', 'Greg', 'Mike', 'James', 'Jason');
$situation = array('Yes');
$html = str_get_html('<table class="mytab">
<tr>
<th>Name</th>
<th>Situation</th>
</tr>
<tr>
<td>
John
</td>
<td class="s">
<strong>Yes</strong>
</td>
</tr>
<tr>
<td>
Allan
</td>
<td class="s">
<strong>No</strong>
</td>
</tr>
<tr>
<td>
James
</td>
<td class="s">
<strong>No</strong>
</td>
</tr>
</table>');
$table = $html->find('table', 0);
$rowData = array();
foreach($table->find('tr') as $row) {
// initialize array to store the cell data from each row
$content= array();
foreach($row->find('td') as $cell) {
// push the cell's text to the array
$content[] = $cell->plaintext;
}
$rowData[] = $content;
}
echo '<table>';
foreach ($rowData as $row => $tr) {
echo '<tr>';
foreach ($tr as $td)
echo '<td>' . $td .'</td>';
echo '</tr>';
}
echo '</table>';
The code above is going to show:
John Yes
Allan No
James No
It's driving me insane I can't figure it out!!
How can I search in the <td>s and get only the people 'Yes' that day?
Assuming your $html is a valid XML string (meaning each tag closes properly, and has a parent tag, and no text outside tags), do this:
$html="<table>..";
$xml = new SimpleXmlElement($html);
$result=array();
foreach($xml->tr as $tr){
//you have your td, see what it has
$name='';
foreach($tr->td as $td) {
if(isset($td->a))
$name=$td->a;
if(isset($td->strong) && $td->strong=='Yes'){
$result[]=strval($name);
}
}
}
print_r($result); //this will have array with name of those where YES
Array
(
[0] => John
)
EDIT: , if you have a well-known XML format of the html, no need to go and check every td. Here I remove nested loop, and reducing complexity from O(n2) to O(n).
$result=array();
foreach($xml->tr as $tr){
//just in case see if a tag is there
if(isset($tr->td[0]->a))
$name = $tr->td[0]->a;
$td2 = $tr->td[1];
if(isset($td2->strong) && $td2->strong=='Yes'){
$result[]=strval($name);
}
}
print_r($result);

Unable to get both child elements with xpath from xhtml using xquery in php to manipulate

The xhtml data I need to get the childNodes from I don't need the child from the TH childNODES
<table>some data</table>
<table>
<tr>
<td class="c2">PCI Signal Error (SERR#) Enable</td>
<td>Yes</td>
</tr>
<tr>
<td class="c1">Controller Type 1</td>
<td>CISS</td>
</tr>
<tr>
<td class="c2">bus type</td>
<td>CISS</td>
</tr>
<tr>
<th><a name="systempcibus5">PCI Bus 31</a></th>
<td>Device</td>
</tr>
</table>
below is the latest attempt, I only want to get the textContent for the TD's in the above xml
so I can build a mysql statement to insert the data in mySql
I have tried so many variations over the last week.
I get this error. I won't bore you with all the various things I tried, but I believe this is the closest to what I want.
PHP Notice: Trying to get property of non-object in C:\inetpub\wwwroot\reports\gec\test1.php on line 40
<?php
libxml_use_internal_errors(true);
$dom = new DomDocument;
$dom->loadHTML($html);
$xpath = new DomXPath($dom);
$nodes = $xpath->query('/html/body/table[2]/tr');
//$nodes = $xpath->query("//tr[contains(concat(' ', #class, ' '), ' head ') ");
//header("Content-type: text/plain");
$node_count=$nodes->length ;
for( $i = 1; $i <= intval($node_count); $i++)
{
$node_td1 = $xpath->query('/html/body/table[2]/tr[$i]/td[1]');
$node_td2 = $xpath->query('/html/body/table[2]/tr[$i]/td[2]');
$result1=$node_td1->textContent;
$result2=$node_td2->textContent;
echo $result1 . "," . $result2 . "<br>";
}
Alternatively, you could just point out the row itself, then filter them out using that ->tagName:
$dom = new DomDocument;
libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_clear_errors();
$xpath = new DomXPath($dom);
$rows = $xpath->query('/html/body/table[2]/tr');
foreach ($rows as $row) {
foreach($row->childNodes as $col) {
if(isset($col->tagName) && $col->tagName != 'th') {
echo $col->textContent . '<br/>';
}
}
echo '<hr/>';
}
Or with using xpath, to reference each row:
foreach ($rows as $row) {
$col1 = $xpath->evaluate('string(./td[1])', $row);
$col2 = $xpath->evaluate('string(./td[2])', $row);
echo $col1 . '<br/>';
echo $col2 . '<br/>';
echo '<hr/>';
}
Sample Output

Parse html table data from DOMXPath

I am scraping data from an external html table that is 100 rows by 3 columns. I want to parse the data into a 10x10 table where the data from each row is combined. Ex:
<tr>
<td>info1</td>
<td>info2</td>
<td>info3</td>
</tr>
<tr>
<td>info4</td>
<td>info5</td>
<td>info6</td>
</tr>
<tr>
<td>info7</td>
<td>info8</td>
<td>info9</td>
</tr>
...and so on
into
<tr>
<td>info1<br/>info2<br/>info3</td>
<td>info4<br/>info5<br/>info6</td>
<td>info7<br/>info8<br/>info9</td>
...7 more times
</tr>
...9 more times
I can output the data into a single column by using line breaks. I have absolutely no idea to do what I want to do above. Also I want to be able to style the data using css. Any help/direction is appreciated. Here is my code:
$doc = new DOMDocument();
$doc->loadHTML($html);
libxml_clear_errors(); //remove errors for yucky html
xpath = new DOMXPath($doc);
$table = $xpath->query('//table[#id="idTable"]')->item(0);
$rows = $table->getElementsByTagName("tr");
foreach($rows as $row)
{
$cells = $row -> getElementsByTagName('td');
foreach ($cells as $cell) print $cell->nodeValue . "<br/>";
}
Two (similar) ways you can do this:
1) By counting the <tr>s and combine each 10 of them, disregard its <td> number:
$doc=new DOMDocument();
$doc->loadHTML($html);
$xpath=new DOMXPath($doc);
echo "<table>\n";
/* 10 is the row count */
for($i=0;$i<10;$i++)
{
echo "<tr>\n";
/* 10 is the column count */
foreach($xpath->query('//table[#id="myTable"]/tr[position()>'.($i*10).' and position()<'.(($i+1)*10+1).']') as $tr)
{
echo "\t<td>";// "\t" to make it look nice
$tds=array();
foreach($tr->childNodes as $td)
{
if($td->nodeName!="td") continue;
$tds[]=$td->firstChild->nodeValue;
}
echo implode("<br />",$tds);
echo "</td>\n";
}
echo "</tr>\n";
}
echo "</table>";
Online demo
2) By counting the <td>s and combine each 3 of them into a new <td>, combine each 30 of them into a new <tr>, disregard the <tr>s:
$doc=new DOMDocument();
$doc->loadHTML($html);
$xpath=new DOMXPath($doc);
echo "<table>\n";
$i=0;
$tds=array();
foreach($xpath->query('//table[#id="myTable"]/tr/td/text()') as $td)
{
/* 30 is each row's old-cell-count */
if($i%30==0) echo "<tr>\n";
$tds[]=$td->nodeValue;
/* 3 is each cell's old-cell-count */
if($i%3==2)
{
echo "\t<td>".implode("<br />",$tds)."</td>\n";
$tds=array();
}
if($i%30==29) echo "</tr>\n";
$i++;
}
echo "</table>";
Online demo
Both outputs:
<table>
<tr>
<td>info0.1<br />info0.2<br />info0.3</td>
<td>info1.1<br />info1.2<br />info1.3</td>
<td>info2.1<br />info2.2<br />info2.3</td>
<td>info3.1<br />info3.2<br />info3.3</td>
<td>info4.1<br />info4.2<br />info4.3</td>
<td>info5.1<br />info5.2<br />info5.3</td>
<td>info6.1<br />info6.2<br />info6.3</td>
<td>info7.1<br />info7.2<br />info7.3</td>
<td>info8.1<br />info8.2<br />info8.3</td>
<td>info9.1<br />info9.2<br />info9.3</td>
</tr>
<tr>
<td>info10.1<br />info10.2<br />info10.3</td>
<td>info11.1<br />info11.2<br />info11.3</td>
<!-- ... -->
<td>info97.1<br />info97.2<br />info97.3</td>
<td>info98.1<br />info98.2<br />info98.3</td>
<td>info99.1<br />info99.2<br />info99.3</td>
</tr>
</table>

How to display a php 3 level array in table form

Currently I have a PHP 3 level array. How do I display it in a table form? Using print_r I could display out the full array but I need to beautify it to show in a table form. Is it possible?
Sample of the array to be inserted is as shown in another posting: PHP foreach with Nested Array?
So... each level of the array should be an embedded table?
<table>
<?php // FIRST LEVEL
foreach ($myArray as $first_level): ?>
<tr>
<td>The header of the first level, here's some data <?php echo $first_level['some_data']; ?></td>
</tr>
<tr>
<td>
<table>
<?php // SECOND LEVEL
foreach($first_level['second_level'] as $second_level): ?>
<tr>
<td><?php echo $second_level['some_data']; ?></td>
</tr>
<?php endforeach; ?>
</table>
</td>
</tr>
<?php endforeach; ?>
</table>
..and keep repeating the pattern
So many ways to do it, even more so since you didn't provide a template for the output format ....
Let's assume each element $e of the input array $src stands for one row in the table.
Then $e[0] is the string element (one, two, three) and $e[1] is the corresponding array 1,2,3, 4,5,6 or 7,8,9.
Let's put $e[0] into <th>...</th> elements.
foreach( $src as $e ) {
echo '<th>', $e[0], '</th>';
}
and then wrap each element in $e[1] in <td>....</td>.
foreach( $src as $e ) {
echo '<th>', $e[0], '</th>';
foreach($e[1] as $v) {
echo '<td>', $v, '</td>';
}
}
now wrap that into another <tr>...</tr> and you are done
foreach( $src as $e ) {
echo '<tr>';
echo '<th>', $e[0], '</th>';
foreach($e[1] as $v) {
echo '<td>', $v, '</td>';
}
echo "</tr>\r\n";
}
the same thing a bit shorter (see http://docs.php.net/join)
<?php
$src = getData();
foreach( $src as $e ) {
echo '<tr><th>', $e[0], '</th><td>', join('</td><td>', $e[1]), "</td></tr>\n";
}
function getData() {
return array(
array( 'one', array(1,2,3) ),
array( 'two', array(4,5,6) ),
array( 'three', array(7,8,9) )
);
}
the output is
<tr><th>one</th><td>1</td><td>2</td><td>3</td></tr>
<tr><th>two</th><td>4</td><td>5</td><td>6</td></tr>
<tr><th>three</th><td>7</td><td>8</td><td>9</td></tr>
see also: http://docs.php.net/htmlspecialchars

Categories