R htmltools browsable HTML does not view without explicit print() - html

I can create HTML code in R that is wrapped with attributes using htmltools package functions. This allows html to be rendered from the console (a browser window is automatically launched) as well as in R Markdown and Quarto documents. But I can't get this to work without an explicit print(). How to make it work with an implicit print? Here is a minimal working example.
require(htmltools)
x <- readLines(textConnection('
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
</table>'))
print.ctest <- function(x) browsable(HTML(x))
class(x) <- 'ctest'
print(x) # opens browser
x # does nothing

If an object is called by its name it uses the default print method for the respective class. Convert x to HTML and call x afterwards it will implicit call print and launch the correct device ( browser)
require(htmltools)
x <- readLines(textConnection('
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
</table>'))
class(x) # [1] "character"
x # prints character in console
x_1 <- browsable(HTML(x))
class(x_1) # [1] "html" "character"
x_1 # shows HTML in browser without explicit print
Edit, to get the implicit print call to work with our custom class use registerS3method to link the method to the class
## change class
class(x) <- 'ctest'
## register its method
registerS3method("print", "ctest",function(x) {print(browsable(HTML(x)))} )
# now the class is recognized and our registered Method is used.
x

Related

Passing HTML to HTML template

I know that if we want to pass variables from .gs to the HTML template, we do this:
On .html (using <?= someVariable ?>:
<div>
<table id="summary">
<thead>
<th>Qty</th>
<th>Item</th>
<th>Price</th>
<th>Subtotal</th>
</thead>
<tbody>
// variable value goes into here
<?= items ?>
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td>Total: </td>
// and into here
<td><b><?= totalCost ?></b></td>
</tr>
</tfoot>
</table>
</div>
And on .gs :
var items = holdSS.getRange(i,5).getValue()
var totalCost = holdSS.getRange(i,6).getValue()
var html = HtmlService.createTemplateFromFile("requestorEmail.html")
// matching the <?= ?> in HTML template
html.items = items
html.totalCost = totalCost
var htmlInString = html.evaluate().getContent()
The size of variable items varies, so I decided to leave it in HTML form, then pass it to the email template. So,
var items = "<tr>
<td>1</td>
<td>3M 500 Scotch Utility Trans. Tape 12mm x 25m</td>
<td>0.98</td>
<td>0.98</td>
</tr>
<tr>
<td>2</td>
<td>3M 558 Bulletin Board - Mocha</td>
<td>19.9</td>
<td>39.80</td>
</tr>
<tr>
<td>1</td>
<td>3M 560RP Post It Marker Rainbow 75mm x 12.5mm 4pad/pkt</td>
<td>3.82</td>
<td>3.82</td>
</tr>"
Resulting in (expected, at least) :
<div>
<table id="summary">
<thead>
<th>Qty</th>
<th>Item</th>
<th>Price</th>
<th>Subtotal</th>
</thead>
<tbody>
// replacing <?= items ?>
<tr>
<td>1</td>
<td>3M 500 Scotch Utility Trans. Tape 12mm x 25m</td>
<td>0.98</td>
<td>0.98</td>
</tr>
<tr>
<td>2</td>
<td>3M 558 Bulletin Board - Mocha</td>
<td>19.9</td>
<td>39.80</td>
</tr>
<tr>
<td>1</td>
<td>3M 560RP Post It Marker Rainbow 75mm x 12.5mm 4pad/pkt</td>
<td>3.82</td>
<td>3.82</td>
</tr>
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td>Total: </td>
// and here
<td><b><?= totalCost ?></b></td>
</tr>
</tfoot>
</table>
</div>
However, console.log(html.evaluate().getContent()) gives :
<tbody>
<tr><td>1</td><td>3M 500 Scotch Utility Trans. Tape 12mm x 25m</td><td>0.98</td><td>0.98</td>
</tr><tr><td>2</td><td>3M 558 Bulletin Board - Mocha</td><td>19.9</td><td>39.80</td></tr>
<tr><td>1</td><td>3M 560RP Post It Marker Rainbow 75mm x 12.5mm 4pad/pkt</td><td>3.82</td><td>3.82</td></tr>
</tbody>
where all the < and > in the HTML tags are escaped. I have read some threads in which they unescape the HTML entities using a textarea element but I also noted I can't execute <script> tags in email clients? What should I do in this case?
When I saw your script, it seems that HTML is put to the template HTML using <?= ... ?> of the printing scriptlets. In this case, such a result in your question is obtained.
In order to put the value as the HTML tag, please use the force-printing scriptlets like <?!= ... ?>. So, please modify it as follows.
From:
<?= items ?>
To:
<?!= items ?>
And, about <?= totalCost ?>, if you want to put the HTML tag, please modify this like <?!= totalCost ?>.
Reference:
HTML Service: Templated HTML

How to format HTML files to get defined names in Excel (copy-paste from web browser)?

At work I am in charge of developing some basic Python scripts which export results into text files. Then the text files are imported into an Excel spreadsheet my colleagues are familiar with.
I realized these Python scripts could easily generate .html files with <table> elements instead of .dat text files. These html files could be opened with the Internet browser and then exported to a new Excel spreadsheet using copy/paste.
Somehow, using the tag <a name=Defined_name></a>Value results in having the cell provided with "Value" being referenced as "Defined_name". I see a great opportunity to upgrade in having defined names directly created when importing a .html web page.
Below is a basic example of a .html file that results in generating defined names in Excel (2007 and over) :
<table>
<tbody> <!-- Corps du tableau -->
<tr>
<td><A name=Nom_1></A>Carmen</td>
<td><A name=Age_1></A>33 ans</td>
<td><A name=Pays_1></A>Espagne</td>
</tr>
<tr>
<td><A name=Nom_2></A>Michelle</a></td>
<td><A name=Age_2></A>26 ans</td>
<td><A name=Pays_2></A>États-Unis</td>
</tr>
<tr>
<td><A name=Nom_3></A>François</td>
<td><A name=Age_3></A>43 ans</td>
<td><A name=Pays_3></A>France</td></A>
</tr>
<tr>
<td><A name=Nom_4></A>Martine</td>
<td><A name=Age_4></A>34 ans</td>
<td><A name=Pays_4></A>France</td>
</tr>
<tr>
<td><A name=Nom_5></A>Jonathan</td>
<td><A name=Age_5></A>13 ans</td>
<td><A name=Pays_5></A>Australie</td>
</tr>
<tr>
<td><A name=Nom_6></A>Xu</td>
<td><A name=Age_6></A>19 ans</td>
<td><A name=Pays_6></A>Chine</td>
</tr>
</tbody>
</table>
I am looking for a way to have defined names for a range of cells (row, column or array). The only things I can reference are single cells.
Thanks for your help.
With openpyxl you could create the workbook using python
import openpyxl
# create a workbook
wb = openpyxl.Workbook()
ws = wb.worksheets[0]
# define a named range
dn = openpyxl.workbook.defined_name
rng = dn.DefinedName('data', attr_text='Sheet!$A$1:$J$10')
wb.defined_names.append(rng)
# add some data
for r in range(1,11):
for c in range (1,11):
ws.cell(r,c).value = r + (c-1)*10
wb.save("myworkbook.xlsx")
print("workbook created")

How to pass raw text from Flask to HTML in the most correct way?

I have a flask app for time series forecasting, I want to show in the HTLM
the result of dataframe.describe():
But, when I pass the content to the html view I get this (the underlined text):
How can I "format" the output of the function, for showing in the most appropiate way?
I'm passing to the template from flask:
return render_template(content = df.describe())
In the Html I have:
{{ content }}
A quick solution could be parse your dataframe as html table
>> import pandas as pd
>> import numpy as np
>> df = pd.DataFrame(np.arange(4).reshape(2, 2), list('AB'), list('XY'))
>> print(df.to_html()) # <- here
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>X</th>
<th>Y</th>
</tr>
</thead>
<tbody>
<tr>
<th>A</th>
<td>0</td>
<td>1</td>
</tr>
<tr>
<th>B</th>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
you can also pass the dateframe to context and iterate with for loop

HTML table design issues

Hi I am trying to create a table with html tags for my requirement but couldn't be able get when I tried.
My requirement is below.
What I am able to get is
Is it possible to get this using html table tags. Kindly help me pls
Simple, with colspan and rowspan see example below.
With colspan you can merge multiple row into one section
colspan
This attribute contains a non-negative integer value that indicates for how many columns the cell extends. Its default value is 1. Values higher than 1000 will be considered as incorrect and will be set to the default value (1).
With rowspan you can merge col into one.
rowspan
This attribute contains a non-negative integer value that indicates for how many rows the cell extends. Its default value is 1; if its value is set to 0, it extends until the end of the table section (<thead>, <tbody>, <tfoot>, even if implicitly defined, that the cell belongs to. Values higher than 65534 are clipped down to 65534.
REF: https://developer.mozilla.org/en/docs/Web/HTML/Element/td
table {
border-spacing: 0;
text-align: center;
}
<table border="1">
<tr>
<th colspan="11">Northern District</th>
</tr>
<tr>
<td rowspan="2">Alfreds Futterkiste</td>
<td rowspan="2">Maria Anders</td>
<td colspan="3">Germany</td>
<td colspan="3">Maria Anders</td>
<td colspan="3">Alfreds Futterkiste</td>
</tr>
<tr>
<td>Centro</td>
<td>Francisco</td>
<td>Mexico</td>
<td>Centro</td>
<td>Francisco</td>
<td>Mexico</td>
<td>Centro</td>
<td>Francisco</td>
<td>Mexico</td>
</tr>
</table>
Search for the HTML attributes colspan and rowspan for td elements - that's what you need in this situation.
(for example here: https://www.w3schools.com/tags/tag_td.asp )
<table>
<tr>
<th colspan=11>Northern District
<tr>
<td rowspan=2>Customers
<td rowspan=2>Salesman
<td colspan=3>Gas
<td colspan=3>Diesel
<td colspan=3>Total
<tr>
<td>Volume
<td>Netback
<td>Profit
<td>Volume
<td>Netback
<td>Profit
<td>Volume
<td>Netback
<td>Profit
</table>

Ignoring tags in XPATH using html agility pack

I am using the following code to parse html tables from an html file into a dataset:
Public Function GetDataSet(html As String) As DataSet
Dim ds As DataSet = New DataSet
Dim htmldoc As New HtmlAgilityPack.HtmlDocument
htmldoc.LoadHtml(html)
Dim tables = htmldoc.DocumentNode.SelectNodes("//table/tr") _
.GroupBy(Function(x) x.ParentNode)
For i As Integer = 0 To tables.Count - 1
Dim rows = tables(i).ToList()
ds.Tables.Add(String.Format("Table {0}", i))
Dim headers = rows(0).Elements("th").Select(Function(x) x.InnerText.Trim).ToList()
For Each Hr In headers
ds.Tables(i).Columns.Add(Hr)
Next
For j As Integer = 1 To rows.Count - 1
Dim row = rows(j)
Dim dr = row.Elements("td").Select(Function(x) x.InnerText.Trim).ToArray()
ds.Tables(i).Rows.Add(dr)
Next
Next
Return ds
End Function
and it works fine. But When There are a Tag placed inside the <Table> Tag before <tr> tag the table is not parsed
Simple Example:
<html>
<head><title>Test</title></head>
<body>
<div>Contents:</div>
<table>
<tr>
<th>Column1</th> <th>Column2</th>
</tr>
<tr>
<td>1</td> <td>11</td>
</tr>
<tr>
<td>2</td> <td>22</td>
</tr>
</table>
<table>
<tbody>
<tr>
<th>Column1</th> <th>Column2</th> <th>Column3</th>
</tr>
<tr>
<td>a</td> <td>aa</td> <td>aaa</td>
</tr>
<tr>
<td>b</td> <td>bb</td> <td>bbb</td>
</tr>
</tbody>
</table>
<table>
<div>
<tr>
<th>Column1</th> <th>Column2</th> <th>Column3</th>
</tr>
<tr>
<td>a</td> <td>aa</td> <td>aaa</td>
</tr>
<tr>
<td>b</td> <td>bb</td> <td>bbb</td>
</tr>
</div>
</table>
</body>
</html>
In This Example only the first table is parsed.
My question is how to ignore any tag between <Table> tag and <tr> tag in the following line of code:
Dim tables = htmldoc.DocumentNode.SelectNodes("//table/tr") _
.GroupBy(Function(x) x.ParentNode)
and all the tables will be parsed.
You can use // to select from all descendants:
Dim rows = htmldoc.DocumentNode.SelectNodes("//table//tr");
Also based on your requirement, it seems it's better to group the result based on the first ancestor table, because the parent of tr may be a tbody or thead and you need to group rows in tables:
Dim tables = htmldoc.DocumentNode.SelectNodes("//table//tr") _
.GroupBy(Function(x) x.Ancestors("table").First())