How to use rowspan with PugJS whilst extracting variables from a JSON object - html-table

I have a json object representing a list of teams and each team has three players. I am using express / pug to create table data.
The input structure is like this:
{ teams: [
team: <string>,
rank: <number>,
members: [
name: <string>,
nationality: <string>,
age: <number>,...
]
],...}
I can see how to generate the cells where the team and all three members are across one row using two each statements:
each val1 in teams
tr
td #{val1.team}
td #{val1.rank}
each val2 in val1.members
td
td #{val2.name}
td #{val2.nationality}
td #{val2.age}
Resulting in one row per team.
|----------|---------–|--------|-----------|-----|--------|-----------|-----|--------|-----------|-----|
| Team | Rank | Name |Nationality| Age | Name |Nationality| Age | Name |Nationality| Age |
|----------|---------–|--------|-----------|-----|--------|-----------|-----|--------|-----------|-----|
But I want to have the three team members above each other like this:
|----------|---------–|--------|-----------|-----|
| | | Name |Nationality| Age |
| | |--------|-----------|-----|
| Team | Rank | Name |Nationality| Age |
| | |--------|-----------|-----|
| | | Name |Nationality| Age |
|----------|---------–|--------|-----------|-----|
this could be done using rowspan cells, but I can't figure out how to map the variables.
<tr>
<td rowspan="3">Team</td>
<td rowspan="3">Rank</td>
<td>Name</td>
<td>Nationality</td>
<td>Age</td>
</tr>
<tr>
<td>Name</td>
<td>Nationality</td>
<td>Age</td>
</tr>
<tr>
<td>Name</td>
<td>Nationality</td>
<td>Age</td>
</tr>
How can I map the json object in PugJS to generate the layout?
regards
Steve

You're very close. It's a matter of getting the indentation right in pug and inserting the rows for each player. Here's a codepen example with the table generated live.
table
each team in teams
tr
td(rowspan= team.members.length + 1)= team.team
td(rowspan= team.members.length + 1)= team.rank
each player in team.members
tr
td= player.name
td= player.nationality
td= player.age

Another way to do this would be to use a tbody element to section off each team, then you can conditionally render the "team" and "rank" cells only in the first row. Setting rowspan="0" on these cells will make them expand the full extent of their tbody section.
Here's a codepen example forked from Graham's pen.
table
each team in teams
tbody
each player, i in team.members
tr
if (i == 0)
th(rowspan='0', scope='row')= team.team
td(rowspan='0')= team.rank
td= player.name
td= player.nationality
td= player.age
Given some data, the above will render:
table,
th,
td {
border: 1px solid black;
}
<table>
<tbody>
<tr>
<th rowspan="0" scope="row">Aberdeen United</th>
<td rowspan="0">1</td>
<td>Adam</td>
<td>Ireland</td>
<td>22</td>
</tr>
<tr>
<td>Bruce</td>
<td>Scotland</td>
<td>23</td>
</tr>
<tr>
<td>Charles</td>
<td>Wales</td>
<td>21</td>
</tr>
</tbody>
</table>

Related

I have words in a cell mixed with word I want to extract. How do I extract the words or delete the words I don't need?

Hello I'm looking for a solution in Pandas or excel. I have a spread sheet with a column that contain words separated by a semicolon
apple - slice123; banana; apple - slice321; orange; citron; apple - slice345;
I want to extract "banana" and "orange" and "citron" into a new column.
I looked for tokenization and pandas extract with word list but I didn't not find a solution.
My original csv contains 1058 rows and the column in question has 1 correct word (orange etc) and 1 error (apple - sliceXYZ) but also 5 correct words and up to 100 errors.
I hope someone has an idea how to solve this.
Edit for clarification.
I have 1027 rows in in the table but only the column with the data of the "fruits" is relevant. I know that I have 27 different fruits somewhere in the columns
Edit: I added a html table for clarification. The word list is used to identify the relevant "fruits" out of the column data and tells me in the results which of the fruits was used in the column data.
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse; padding: 15px;
}
</style>
<table>
<tr>
<td><p><strong>Colunmn 1</strong></p></td>
<td><p><strong>Colunmn 2</strong></p></td>
<td><p><strong>Data</strong></p></td>
<td><p><strong>Result</strong></p></td>
</tr>
<tr>
<td><p>not relevant</p></td>
<td><p>not relevant</p></td>
<td><p>apple - slice123; banana; apple - slice321; orange; citron; apple - slice345</p></td>
<td><p>banana; orange; citron</p></td>
</tr>
<tr>
<td><p>not relevant</p></td>
<td><p>not relevant</p></td>
<td><p>apple - slice435; banana; apple - slice687; orange; citron; apple - slice334; mango; papaya</p></td>
<td><p>banana; orange; citron; mango; papaya</p></td>
</tr>
</table>
<p></p>
<table>
<tr>
<td><p> <strong>word list</strong><p></td>
</tr>
<tr>
<td><p>banana</p></td>
</tr>
<tr>
<td><p>orange<p></td>
</tr>
<tr>
<td><p>citron<p></td>
</tr>
<tr>
<td><p>mango<p></td>
</tr>
<tr>
<td><p>papaya<p></td>
</tr>
</table>
IIUC you can do it like this:
df = pd.DataFrame(
{
"Col2": ["not relevant", "not relevant"],
"Data": [
"apple - slice123; banana; apple - slice321; orange; citron; apple - slice345;",
"apple - slice435; banana; apple - slice687; orange; citron; apple - slice334; mango; papaya",
],
}
)
word_list = ['banana', 'orange', 'citron', 'mango', 'papaya']
two options:
a)
df["Result"] = df["Data"].map(
lambda s: ";".join(
filter(None, [x.strip() for x in s.split(";") if "slice" not in x])
)
)
b)
df["Result"] = df["Data"].map(
lambda s: ";".join(
filter(None, [x.strip() for x in s.split(";") if x.strip() in word_list])
)
)
print(df['Result']
0 banana;orange;citron
1 banana;orange;citron;mango;papaya
Name: Result, dtype: object
If you have Excel 2019 (or greater) and the first cell with data is A1 you could use
=TEXTJOIN("; ",TRUE,(FILTERXML("<c><e>"&SUBSTITUTE(A1,";","</e><e>")&"</e></c>","//e[node() and not(contains(., '-'))]")))
If you have Excel 2013 to 2016 then you could just use the FILTERXML() portion of the above, but it would have to be entered as an array formula, e.g. select cells B1:D1, enter the formula in the formula bar, and press CTRL+Shift+Enter to confirm it
(you're selecting 3 cells because you expect to have 3 results)

how to apply filter on JQuery DataTable each columns? [duplicate]

I'm trying to filter table rows in an intelligent way (as opposed to just tons of code that get the job done eventually) but a rather dry of inspiration.
I have 5 columns in my table. At the top of each there is either a dropdown or a textbox with which the user may filter the table data (basically hide the rows that don't apply)
There are plenty of table filtering plugins for jQuery but none that work quite like this, and thats the complicated part :|
Here is a basic filter example http://jsfiddle.net/urf6P/3/
It uses the jquery selector :contains('some text') and :not(:contains('some text')) to decide if each row should be shown or hidden. This might get you going in a direction.
EDITED to include the HTML and javascript from the jsfiddle:
$(function() {
$('#filter1').change(function() {
$("#table td.col1:contains('" + $(this).val() + "')").parent().show();
$("#table td.col1:not(:contains('" + $(this).val() + "'))").parent().hide();
});
});
Slightly enhancing the accepted solution posted by Jeff Treuting, filtering capability can be extended to make it case insensitive. I take no credit for the original solution or even the enhancement. The idea of enhancement was lifted from a solution posted on a different SO post offered by Highway of Life.
Here it goes:
// Define a custom selector icontains instead of overriding the existing expression contains
// A global js asset file will be a good place to put this code
$.expr[':'].icontains = function(a, i, m) {
return $(a).text().toUpperCase()
.indexOf(m[3].toUpperCase()) >= 0;
};
// Now perform the filtering as suggested by #jeff
$(function() {
$('#filter1').on('keyup', function() { // changed 'change' event to 'keyup'. Add a delay if you prefer
$("#table td.col1:icontains('" + $(this).val() + "')").parent().show(); // Use our new selector icontains
$("#table td.col1:not(:icontains('" + $(this).val() + "'))").parent().hide(); // Use our new selector icontains
});
});
This may not be the best way to do it, and I'm not sure about the performance, but an option would be to tag each column (in each row) with an id starting with a column identifier and then a unique number like a record identifier.
For example, if you had a column Produce Name, and the record ID was 763, I would do something like the following:
​​<table id="table1">
<thead>
<tr>
<th>Artist</th>
<th>Album</th>
<th>Genre</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td id="artist-127">Red Hot Chili Peppers</td>
<td id="album-195">Californication</td>
<td id="genre-1">Rock</td>
<td id="price-195">$8.99</td>
</tr>
<tr>
<td id="artist-59">Santana</td>
<td id="album-198">Santana Live</td>
<td id="genre-1">Rock</td>
<td id="price-198">$8.99</td>
</tr>
<tr>
<td id="artist-120">Pink Floyd</td>
<td id="album-183">Dark Side Of The Moon</td>
<td id="genre-1">Rock</td>
<td id="price-183">$8.99</td>
</tr>
</tbody>
</table>
You could then use jQuery to filter based on the start of the id.
For example, if you wanted to filter by the Artist column:
var regex = /Hot/;
$('#table1').find('tbody').find('[id^=artist]').each(function() {
if (!regex.test(this.innerHTML)) {
this.parentNode.style.backgroundColor = '#ff0000';
}
});
You can filter specific column by just adding children[column number] to JQuery filter. Normally, JQuery looks for the keyword from all the columns in every row. If we wanted to filter only ColumnB on below table, we need to add childern[1] to filter as in the script below. IndexOf value -1 means search couldn't match. Anything above -1 will make the whole row visible.
ColumnA | ColumnB | ColumnC
John Doe 1968
Jane Doe 1975
Mike Nike 1990
$("#myInput").on("change", function () {
var value = $(this).val().toLowerCase();
$("#myTable tbody tr").filter(function () {
$(this).toggle($(this.children[1]).text().toLowerCase().indexOf(value) > -1)
});
});
step:1 write the following in .html file
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
</table>
step:2 write the following in .js file
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}

Get specific value based on column & row name from dynamic Web table in which columns & rows position also dynamic

I have to print a specific value based on column and row names.
Bt the problem is that columns position and rows position changes every time. And table data is dynamic, values are changing continuously. All the values are not constantmy dynamic web table is. and i want specific value of month April in year 2001.
Here is the sample table based on the attached screenshot.
<html>
<table id='table1' border=" 1px solid black">
<tr>
<th>Month/Year</th>
<th>2003</th>
<th>2004</th>
<th>2001</th>
<th>2005</th>
<th>2002</th>
</tr>
<tr>
<td>May</td>
<td>122</td>
<td>84</td>
<td>7777</td>
<td>12</td>
<td>122</td>
</tr>
<tr>
<td>Feb</td>
<td>45</td>
<td>445</td>
<td>565</td>
<td>222</td>
<td>122</td>
</tr>
<tr>
<td>April</td>
<td>3556</td>
<td>212</td>
<td>21</td>
<td>1546</td>
<td>855</td>
</tr>
</table>
<span>-----------------------------------------------</span>
<table id='table2' border=" 1px solid black">
<tr>
<th>Month/Year</th>
<th>2002</th>
<th>2001</th>
<th>2003</th>
<th>2004</th>
<th>2005</th>
</tr>
<tr>
<td>April</td>
<td>120</td>
<td>243</td>
<td>221</td>
<td>21</td>
<td>65</td>
</tr>
<tr>
<td>May</td>
<td>96</td>
<td>146</td>
<td>454</td>
<td>452</td>
<td>4566</td>
</tr>
<tr>
<td>March</td>
<td>788</td>
<td>139</td>
<td>10</td>
<td>1001</td>
<td>013</td>
</tr>
<tr>
<td>Feb</td>
<td>552</td>
<td>1245</td>
<td>545</td>
<td>41</td>
<td>41</td>
</tr>
</table>
</html>
Below is the xpath to get the value of "April/2001" from table 1.
//table[#id='table1']//td[position()=count(//th[normalize-space(.)='Month/Year']/preceding-sibling::th)+1 and normalize-space(.)='April']/ancestor::tr//td[position()=count(//table[#id='table1']//th[normalize-space(.)='2001']/preceding-sibling::th)+1]
And xpath to get the value of "April/2001" from table 2.
//table[#id='table2']//td[position()=count(//th[normalize-space(.)='Month/Year']/preceding-sibling::th)+1 and normalize-space(.)='April']/ancestor::tr//td[position()=count(//table[#id='table2']//th[normalize-space(.)='2001']/preceding-sibling::th)+1]
The only difference between the 2 xpaths' above is table id **//table[#id='tableX**. Please update the table locator as per your application values.
Let me know if this is helpful.

Beautifulsoup Table Scraping table navigation

I am trying to learn beautifulsoup to scrap HTML and have a difficult challenge.
HTML I am trying to scrap is not well formatted and with lack of knowledge with beautifulsoup I am kind of stuck..
The HTML I am trying to scrap is as below
<table>
<tr>
<td><b>Value 1<b/>HiddenValue1</td>
<td>Value 2</td>
</tr>
<tr>
<td>NoValue</td>
</tr>
<tr>
<td><b>Value 3<b/>HiddenValue2</td>
<td>Value 4</td>
</tr>
</table>
So the outcome I am trying to get is extract all rows with two td tags.
This will extract the first and the last tr.
Once I get them, I need to arrange these td and b and just text into dictionary.
My desired outcome is list of dictionary
[
{ tdb : 'Value 1', tdHidden : 'HiddenValue1', tdSecond : 'Value 2' },
{ tdb : 'Value 3', tdHidden : 'HiddenValue2', tdSecond : 'Value 4' },
]
I am trying to use findall() function but don't know how to check length of children td tags and also not to sure how to navigate to first td and second td ..
Thanks in advance for your help !
EDIT :
Could you please also help with how to get "GetThisValue" and "Current" with in the td tag?
<td align="left" valign="top">
<b>Value1</b>
<br>
<font>
<b>Current</b>
</font>
<br>
GetThisValue
</td>
Following code should work -
trs = soup.find('table').find_all('tr')
trs = [tr for tr in trs if len(tr.find_all('td')) == 2]
results = []
for tr in trs:
tds = tr.find_all('td')
d = {
'tdb': tds[0].b.text,
'tdHidden': tds[0].b.next_sibling,
'tdSecond': tds[1].text
}
results.append(d)
Answer2 for the EDIT part -
# GetThisValue
soup.find('td').find_all('br')[1].next_sibling
# Current
soup.find('td').find('font').b.text

PHPTAL and specific table

I have to create specific table in PHPTAL.
I have array like that:
$tab = array('item1', 'item2', 'item3', 'item4');
Final table should be look like that:
<table>
<tr>
<td>Item1</td>
<td>Item2</td>
</tr>
<tr>
<td>Item3</td>
<td>Item4</td>
</tr>
</table>
So I was trying use tal:condition width "repeat/item/odd" and "repeat/item/even" to fit < tr > tag in right place, but it not working that I want to.
Have you any ideas?
<tr tal:repeat="row php:array_chunk(tab, 2)">