Html
The Html module can be used to parse and query html formatted files and remote pages. It also contains encoding/decoding helper methods for html.
Requires Manatee v2.1 or greater
This version of the Html module cannot be used with Manatee v2.0 or earlier.
Loading data
The methods load and loadFrom can be used to load and parse a html document. They both return a HtmlDoc object which can be used for querying/extracting information.
// Load html from a string
var doc = Html.load("<html><body>Hello, world!</body></html>");
// Load html from an url
doc = Html.loadFrom("http://sirenia.eu");Html.encode
Use this method to encode a string to replace unicode characters etc with their html encoded counterparts.
var encoded = Html.encode("1 < 2");
// encoded is now "1 < 2"Html.decode
Decode an already html encoded string also includes html5 named entities in the decoding.
var decoded = Html.decode("1 < 2 = Å");
// decoded is now "1 < 2 = Å"Html.btoa
Encode a string to base64.
var encoded = Html.btoa("Hello, world!");
// encoded is now "SGVsbG8sIHdvcmxkIQ=="Html.atob
Decode a base64 encoded string.
var decoded = Html.atob("SGVsbG8sIHdvcmxkIQ==");
// decoded is now "Hello, world!"HtmlDoc
The HtmlDoc object return from Html.load and .loadFrom has two primary methods for querying and extracting information from the html document it represents - the first is via an XPath query and the second is to convert the html to json.
XPath
The xpath method can be used to query the HtmlDoc with a given XPath query. All innerTexts are html decoded strings.
xpath always returns an array, even when the expression matches a single node, so index into it:
var d = Html.load("<html><body>Hello</body>");
var body = d.xpath("//body")[0];
Debug.showDialog(body.innerText); // shows "Hello"Use querySelector instead if you want the first match directly. If the expression cannot be evaluated, xpath returns null rather than an empty array.
Converting to json
Converting the html to json is done with the .json() method. Each node in the resulting tree of objects has the following properties:
attrsan object containing the attributes of the html nodechildrenis an array of child json nodesinnerTextis a textual representation of the contents of the node (html decoded)tagNameis the name of the original html node
It also has xpath, querySelector and querySelectorAll methods which can be used to query the subtree of the json node as is possible for the HtmlDoc object.
var d = Html.load("<html><body>Hello</body>");
var json = d.json();
Debug.showDialog(json.tagName);The json() function can also include #text nodes.
var d = Html.load("<html><body>He<br>llo</body>");
var json = d.json({ includeTextNodes: true });This allows for better reconstruction of the original html using the html() function (perhaps after modifying).
var d = Html.load("<html><body>Hello</body>");
var json = d.json();
// Now we get back the original html (if possible)
var html = json.html();html() serialises the node’s contents, not the node
Pass includeRoot to have the node included:
var body = d.querySelector("body");
body.html(); // the markup inside <body>
body.html({ includeRoot: true }); // <body>…</body>QuerySelectorAll
Use the querySelectorAll method to query the HtmlDoc using CSS selectors.
// We'll assume we have a `HtmlDoc` object in `d`
var myClassDivs = d.querySelectorAll("div.myClass");QuerySelector
The querySelector works similarly to the querySelectorAll except it returns the first hit only.
Table
The table(...) function can be used to extract js objects from html tables.
Given the table:
<table id="myTable">
<thead>
<tr><th>A</th></tr>
</thead>
<tbody>
<tr><td>100</td></tr>
<tr><td>200</td></tr>
</tbody>
</table>We can use the table function as follows:
// Assume we have the html already loaded in `d`
var t = d.table("#myTable");
// and now we can query the contents of the table as follows
var firstRowFirstColumn = t.rows[0]["A"];The result also carries a header array, holding the column names in order.
If the table has no header information, rows holds a plain array per row instead of an object keyed by column name. So t.rows[0][0] rather than t.rows[0]["A"].
We can also use an object to pinpoint the header and/or the body of the table. This is useful if we have on our hands a table where the header is one location while the data is somewhere else. This is often the case for scrollable tables.
<table id="myTableHeader">
<thead>
<tr><th>A</th></tr>
</thead>
</table>
<table id="myTableBody">
<tbody>
<tr><td>100</td></tr>
<tr><td>200</td></tr>
</tbody>
</table>Now do this:
// Assume we have the html already loaded in `d`
var t = d.table(
{
tableAt: "#myTableBody",
headerAt: "#myTableHeader thead tr th",
rowAt: "#myTableBody tbody tr",
cellAt: "td"
}
);
// and now we can (again) query the contents of the table as follows
var firstRowFirstColumn = t.rows[0]["A"];headerAt needs to point out the individual header elements, typically th elements, while rowAt must point out the tr elements in the table. cellAt selects the cells within each row.
The defaults
Every one of the four is optional. Passing a plain string, as in d.table("#myTable"), sets tableAt and leaves the rest at their defaults, which are derived from it:
| option | default |
|---|---|
tableAt | table, [role='table'] |
headerAt | <tableAt> thead tr:first-child th, or <tableAt> [role='columnheader'] |
rowAt | <tableAt> tbody tr, or <tableAt> [role='row']. If neither matches, <tableAt> tr is tried |
cellAt | td, [role='cell'], resolved within each row |
The ARIA alternates mean table(...) also reads grids built from role attributes rather than real table elements.
Always say which table
tableAt defaults to table, [role='table'], meaning any table or ARIA grid in the document. On a page with more than one, pass a selector that identifies the table you mean.
