KEMBAR78
{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": null, "outputs": [], "source": [ "#r \"nuget: FSharp.Data,6.6.0\"\n", "\n", "Formatter.SetPreferredMimeTypesFor(typeof\u003cobj\u003e, \"text/plain\")\n", "Formatter.Register(fun (x: obj) (writer: TextWriter) -\u003e fprintfn writer \"%120A\" x)\n", "#endif\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "[![Binder](../img/badge-binder.svg)](https://mybinder.org/v2/gh/fsprojects/FSharp.Data/gh-pages?filepath=library/HtmlCssSelectors.ipynb)\u0026emsp;\n", "[![Script](../img/badge-script.svg)](https://fsprojects.github.io/FSharp.Data//library/HtmlCssSelectors.fsx)\u0026emsp;\n", "[![Notebook](../img/badge-notebook.svg)](https://fsprojects.github.io/FSharp.Data//library/HtmlCssSelectors.ipynb)\n", "\n", "# HTML CSS selectors\n", "\n", "This article demonstrates how to use HTML CSS selectors to browse the DOM of parsed HTML files.\n", "We use the [HtmlDocument](https://fsprojects.github.io/FSharp.Data/reference/fsharp-data-htmldocument.html) type and associated [HtmlDocument](https://fsprojects.github.io/FSharp.Data/reference/fsharp-data-htmldocumentmodule.html) module\n", "and [HtmlDocumentExtensions](https://fsprojects.github.io/FSharp.Data/reference/fsharp-data-htmldocumentextensions.html) extensions.\n", "\n", "The usage of CSS selectors is a very natural way to parse HTML when we come from Web developments.\n", "The HTML CSS selectors are based on the [JQuery selectors](https://api.jquery.com/category/selectors/).\n", "To use CSS selectors, reference the FSharp.Data package. You then need to open `FSharp.Data` namespace, which\n", "automatically exposes extension methods that implement the CSS selectors.\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 2, "outputs": [], "source": [ "open FSharp.Data\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "## Practice 1: Search for FSharp.Data on Google\n", "\n", "We will parse links of a Google to search for `FSharp.Data` like in the [HTML Parser](HtmlParser.html) article.\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 3, "outputs": [ { "data": { "text/plain": ["val googleUrl: string = \"http://www.google.co.uk/search?q=FSharp.Data\"", "", "val doc: HtmlDocument =", "", " \u003c!DOCTYPE html\u003e", "", "\u003chtml lang=\"en\"\u003e", "", " \u003chead\u003e", "", " \u003ctitle\u003eGoogle Search\u003c/title\u003e\u003cstyle\u003ebody{background-color:#fff}\u003c/style\u003e\u003cscript nonce=\"uFatOq1P3Hz00p6HncT_Yw\"\u003ewindow.google = window.google || {};window.google.c = window.google.c || {ezx:false,cap:0};\u003c/script\u003e", "", " \u003c/head\u003e", "", " \u003cbody\u003e", "", " \u003cnoscript\u003e", "", " \u003cstyle\u003etable,div,span,p{display:none}\u003c/style\u003e\u003cmeta content=\"0;url=/httpservice/retry/enablejs?sei=17O1aNyIMPCmmtkP8ZC3wAY\" http-equiv=\"refresh\" /\u003e", "", " \u003cdiv style=\"display:block\"\u003e", "", " Please click \u003ca..."] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" }], "source": [ "let googleUrl = \"http://www.google.co.uk/search?q=FSharp.Data\"\n", "let doc = HtmlDocument.Load(googleUrl)\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "To make sure we extract search results only, we will parse links in the `\u003cdiv\u003e` with id `search`.\n", "Then we can, for example, use the direct descendants selector to select another `\u003cdiv\u003e` with the\n", "id `ires`. The CSS selector to do so is `div#search \u003e div#ires`:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 4, "outputs": [ { "data": { "text/plain": ["val links: string list = []"] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" }], "source": [ "let links =\n", " doc.CssSelect(\"div#search \u003e div#ires div.g \u003e div.s div.kv cite\")\n", " |\u003e List.map (fun n -\u003e\n", " match n.InnerText() with\n", " | t when (t.StartsWith(\"https://\") || t.StartsWith(\"http://\")) -\u003e t\n", " | t -\u003e \"http://\" + t)\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "The rest of the selector (written as `li.g \u003e div.s`) skips the first 4 sub-results targeting GitHub pages,\n", "so we only extract proper links.\n", "\n", "Now, we might want the page titles associated with their URLs. To do this, we can use the `List.zip` function:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 5, "outputs": [ { "data": { "text/plain": ["val searchResults: (string * string) list = []"] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" }], "source": [ "let searchResults =\n", " doc.CssSelect(\"div#search \u003e div#ires div.g \u003e h3\")\n", " |\u003e List.map (fun n -\u003e n.InnerText())\n", " |\u003e List.zip (links)\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "## Practice 2: Search F# books on Google Books\n", "\n", "We will parse links of the Google Books web site, searching for `F#`. After downloading the document,\n", "we simply ensure to match good links with their CSS\u0027s styles and DOM\u0027s hierarchy. In case of Google Books,\n", "we need to look for `\u003cdiv\u003e` with `class` set to `g`, then for `\u003ch3\u003e` with CSS class `r` and then for all `\u003ca\u003e` elements:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 6, "outputs": [ { "data": { "text/plain": ["val fsys: string = \"https://www.google.com/search?tbm=bks\u0026q=F%23\"", "", "val doc2: HtmlDocument =", "", " \u003c!-- html\u003e--\u003e\u003chtml lang=\"en\"\u003e", "", " \u003chead\u003e", "", " \u003cmeta charset=\"UTF-8\" /\u003e\u003cmeta content=\"/images/branding/googleg/1x/googleg_standard_color_128dp.png\" itemprop=\"image\" /\u003e\u003ctitle\u003eF# - Google Search\u003c/title\u003e\u003cscript nonce=\"NsKbGYg1PWVXk-YsW7FuvQ\"\u003e(function(){", "document.documentElement.addEventListener(\"submit\",function(b){var a;if(a=b.target){var c=a.getAttribute(\"data-submitfalse\");a=c===\"1\"||c===\"q\"\u0026\u0026!a.elements.q.value?!0:!1}else a=!1;a\u0026\u0026(b.preventDefault(),b.stopPropagation())},!0);document.documentElement.addE...", "", "val books: (string * string) list = []"] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" }], "source": [ "let fsys = \"https://www.google.com/search?tbm=bks\u0026q=F%23\"\n", "let doc2 = HtmlDocument.Load(fsys)\n", "\n", "let books =\n", " doc2.CssSelect(\"div.g h3.r a\")\n", " |\u003e List.map (fun a -\u003e a.InnerText().Trim(), a.AttributeValue(\"href\"))\n", " |\u003e List.filter (fun (title, href) -\u003e title.Contains(\"F#\"))\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "## JQuery selectors\n", "\n", "This section provides a quick overview of the supported CSS selectors. If you are familiar\n", "with CSS selectors in JQuery, then you will see that most of the features are the same.\n", "You can also refer to the table below for a complete list of supported selectors.\n", "\n", "### Attribute Contains Prefix Selector\n", "\n", "Finds all links with an English hreflang attribute.\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 7, "outputs": [ { "data": { "text/plain": ["val englishDoc: HtmlDocument =", "", " \u003c!-- html\u003e--\u003e\u003chtml lang=\"en\"\u003e", "", " \u003cbody\u003e", "", " \u003ca href=\"example.html\" hreflang=\"en\"\u003eSome text\u003c/a\u003e\u003ca href=\"example.html\" hreflang=\"en-UK\"\u003eSome other text\u003c/a\u003e\u003ca href=\"example.html\" hreflang=\"english\"\u003ewill not be outlined\u003c/a\u003e", "", " \u003c/body\u003e", "", "\u003c/html\u003e", "", "val englishLinks: HtmlNode list =", "", " [\u003ca href=\"example.html\" hreflang=\"en\"\u003eSome text\u003c/a\u003e;", "", " \u003ca href=\"example.html\" hreflang=\"en-UK\"\u003eSome other text\u003c/a\u003e]"] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" }], "source": [ "let englishDoc =\n", " HtmlDocument.Parse(\n", " \"\"\"\n", " \u003c!doctype html\u003e\n", " \u003chtml lang=\"en\"\u003e\n", " \u003cbody\u003e\n", " \u003ca href=\"example.html\" hreflang=\"en\"\u003eSome text\u003c/a\u003e\n", " \u003ca href=\"example.html\" hreflang=\"en-UK\"\u003eSome other text\u003c/a\u003e\n", " \u003ca href=\"example.html\" hreflang=\"english\"\u003ewill not be outlined\u003c/a\u003e\n", " \u003c/body\u003e\n", " \u003c/html\u003e\"\"\"\n", " )\n", "\n", "let englishLinks = englishDoc.CssSelect(\"a[hreflang|=en]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute Contains Selector\n", "\n", "Finds all inputs with a name containing \"man\". This includes results where \"man\" is a substring:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 8, "outputs": [ { "data": { "text/plain": ["val manDoc: HtmlDocument =", "", " \u003c!-- html\u003e--\u003e\u003chtml lang=\"en\"\u003e", "", " \u003cbody\u003e", "", " \u003cinput name=\"man-news\" /\u003e\u003cinput name=\"milkman\" /\u003e\u003cinput name=\"milk man\" /\u003e\u003cinput name=\"letterman2\" /\u003e\u003cinput name=\"newmilk\" /\u003e\u003cinput name=\"man\" /\u003e\u003cinput name=\"newsletter\" /\u003e", "", " \u003c/body\u003e", "", "\u003c/html\u003e", "", "val manElems: HtmlNode list =", "", " [\u003cinput name=\"man-news\" /\u003e; \u003cinput name=\"milkman\" /\u003e;", "", " \u003cinput name=\"milk man\" /\u003e; \u003cinput name=\"letterman2\" /\u003e;", "", " \u003cinput name=\"man\" /\u003e]"] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" }], "source": [ "let manDoc =\n", " HtmlDocument.Parse(\n", " \"\"\"\n", " \u003c!doctype html\u003e\n", " \u003chtml lang=\"en\"\u003e\n", " \u003cbody\u003e\n", " \u003cinput name=\"man-news\"\u003e\n", " \u003cinput name=\"milkman\"\u003e\n", " \u003cinput name=\"milk man\"\u003e\n", " \u003cinput name=\"letterman2\"\u003e\n", " \u003cinput name=\"newmilk\"\u003e\n", " \u003cinput name=\"man\"\u003e\n", " \u003cinput name=\"newsletter\"\u003e\n", " \u003c/body\u003e\n", " \u003c/html\u003e\"\"\"\n", " )\n", "\n", "let manElems = manDoc.CssSelect(\"input[name*=\u0027man\u0027]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute Contains Word Selector\n", "\n", "Finds all inputs with a name containing the word \"man\". This requires a whitespace around the word:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 9, "outputs": [ { "data": { "text/plain": ["val manWordElems: HtmlNode list =", "", " [\u003cinput name=\"milk man\" /\u003e; \u003cinput name=\"man\" /\u003e]"] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" }], "source": [ "let manWordElems = manDoc.CssSelect(\"input[name~=\u0027man\u0027]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute Ends With Selector\n", "\n", "Finds all inputs with a name ending with \"man\".\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 10, "outputs": [ { "data": { "text/plain": ["val manEndElemes: HtmlNode list =", "", " [\u003cinput name=\"milkman\" /\u003e; \u003cinput name=\"milk man\" /\u003e; \u003cinput name=\"man\" /\u003e]"] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" }], "source": [ "let manEndElemes = manDoc.CssSelect(\"input[name$=\u0027man\u0027]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute Equals Selector\n", "\n", "Finds all inputs with a name equal to \"man\".\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 11, "outputs": [ { "data": { "text/plain": ["val manEqElemes: HtmlNode list = [\u003cinput name=\"man\" /\u003e]"] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }], "source": [ "let manEqElemes = manDoc.CssSelect(\"input[name=\u0027man\u0027]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute Not Equal Selector\n", "\n", "Finds all inputs with a name different to \"man\".\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 12, "outputs": [ { "data": { "text/plain": ["val notManElems: HtmlNode list =", "", " [\u003cinput name=\"man-news\" /\u003e; \u003cinput name=\"milkman\" /\u003e;", "", " \u003cinput name=\"milk man\" /\u003e; \u003cinput name=\"letterman2\" /\u003e;", "", " \u003cinput name=\"newmilk\" /\u003e; \u003cinput name=\"newsletter\" /\u003e]"] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" }], "source": [ "let notManElems = manDoc.CssSelect(\"input[name!=\u0027man\u0027]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute Starts With Selector\n", "\n", "Finds all inputs with a name starting with \"man\".\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 13, "outputs": [ { "data": { "text/plain": ["val manStartElems: HtmlNode list =", "", " [\u003cinput name=\"man-news\" /\u003e; \u003cinput name=\"man\" /\u003e]"] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" }], "source": [ "let manStartElems = manDoc.CssSelect(\"input[name^=\u0027man\u0027]\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "### Forms helpers\n", "\n", "There are some syntax shortcuts to find forms controls.\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 14, "outputs": [], "source": [ "let htmlForm =\n", " HtmlDocument.Parse(\n", " \"\"\"\n", " \u003c!doctype html\u003e\n", " \u003chtml\u003e\n", " \u003cbody\u003e\n", " \u003cform\u003e\n", " \u003cfieldset\u003e\n", " \u003cinput type=\"button\" value=\"Input Button\"\u003e\n", " \u003cinput type=\"checkbox\" id=\"check1\"\u003e\n", " \u003cinput type=\"hidden\" id=\"hidden1\"\u003e\n", " \u003cinput type=\"password\" id=\"pass1\"\u003e\n", " \u003cinput name=\"email\" disabled=\"disabled\"\u003e\n", " \u003cinput type=\"radio\" id=\"radio1\"\u003e\n", " \u003cinput type=\"checkbox\" id=\"check2\" checked=\"checked\"\u003e\n", " \u003cinput type=\"file\" id=\"uploader1\"\u003e\n", " \u003cinput type=\"reset\"\u003e\n", " \u003cinput type=\"submit\"\u003e\n", " \u003cinput type=\"text\"\u003e\n", " \u003cselect\u003e\u003coption\u003eOption\u003c/option\u003e\u003c/select\u003e\n", " \u003ctextarea class=\"comment box1\"\u003eType a comment here\u003c/textarea\u003e\n", " \u003cbutton\u003eGo !\u003c/button\u003e\n", " \u003c/fieldset\u003e\n", " \u003c/form\u003e\n", " \u003c/body\u003e\n", " \u003c/html\u003e\"\"\"\n", " )\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "You can use `:prop` to find CSS elements with the specified value of the `type` attribute\n", "or a specified form control property. This lets you easily select all buttons, checkboxes,\n", "radio buttons, but also hidden or disabled form elements:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": 15, "outputs": [ { "data": { "text/plain": ["val buttons: HtmlNode list =", "", " [\u003cbutton\u003eGo !\u003c/button\u003e; \u003cinput type=\"button\" value=\"Input Button\" /\u003e]", "", "val checkboxes: HtmlNode list =", "", " [\u003cinput type=\"checkbox\" id=\"check1\" /\u003e;", "", " \u003cinput type=\"checkbox\" id=\"check2\" checked=\"checked\" /\u003e]", "", "val checkd: HtmlNode list =", "", " [\u003cinput type=\"checkbox\" id=\"check2\" checked=\"checked\" /\u003e]", "", "val disabled: HtmlNode list = [\u003cinput name=\"email\" disabled=\"disabled\" /\u003e]", "", "val hidden: HtmlNode list = [\u003cinput type=\"hidden\" id=\"hidden1\" /\u003e]", "", "val radio: HtmlNode list = [\u003cinput type=\"radio\" id=\"radio1\" /\u003e]", "", "val password: HtmlNode list = [\u003cinput type=\"password\" id=\"pass1\" /\u003e]", "", "val file: HtmlNode list = [\u003cinput type=\"file\" id=\"uploader1\" /\u003e]"] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" }], "source": [ "// Find all buttons.\n", "let buttons = htmlForm.CssSelect(\":button\")\n", "\n", "// Find all checkboxes.\n", "let checkboxes = htmlForm.CssSelect(\":checkbox\")\n", "\n", "// Find all checked checkboxs or radio.\n", "let checkd = htmlForm.CssSelect(\":checked\")\n", "\n", "// Find all disabled controls.\n", "let disabled = htmlForm.CssSelect(\":disabled\")\n", "\n", "// Find all inputs with type hidden.\n", "let hidden = htmlForm.CssSelect(\":hidden\")\n", "\n", "// Find all inputs with type radio.\n", "let radio = htmlForm.CssSelect(\":radio\")\n", "\n", "// Find all inputs with type password.\n", "let password = htmlForm.CssSelect(\":password\")\n", "\n", "// Find all files uploaders.\n", "let file = htmlForm.CssSelect(\":file\")\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "## Implemented and missing features\n", "\n", "Basic CSS selectors are implemented, but some JQuery selectors are missing\n", "\n", "This table lists all JQuery selectors and their status\n", "\n", "Selector name | Status | specification\n", "--- | :---: | ---:\n", "*All Selector * | `TODO` | [specification](http://api.jquery.com/all-selector/)\n", "**:animated Selector** | `not possible` | [specification](http://api.jquery.com/animated-selector/)\n", "**Attribute Contains Prefix Selector** | `implemented` | [specification](http://api.jquery.com/attribute-contains-prefix-selector/)\n", "*Attribute Contains Selector * | `implemented` | [specification](http://api.jquery.com/attribute-contains-selector/)\n", "**Attribute Contains Word Selector** | `implemented` | [specification](http://api.jquery.com/attribute-contains-word-selector/)\n", "*Attribute Ends With Selector * | `implemented` | [specification](http://api.jquery.com/attribute-ends-with-selector/)\n", "*Attribute Equals Selector * | `implemented` | [specification](http://api.jquery.com/attribute-equals-selector/)\n", "**Attribute Not Equal Selector** | `implemented` | [specification](http://api.jquery.com/attribute-not-equal-selector/)\n", "*Attribute Starts With Selector * | `implemented` | [specification](http://api.jquery.com/attribute-starts-with-selector/)\n", "*:button Selector * | `implemented` | [specification](http://api.jquery.com/button-selector/)\n", "**:checkbox Selector** | `implemented` | [specification](http://api.jquery.com/checkbox-selector/)\n", "**:checked Selector** | `implemented` | [specification](http://api.jquery.com/checked-selector/)\n", "**Child Selector (“parent \u0026gt; child”)** | `implemented` | [specification](http://api.jquery.com/child-selector/)\n", "**Class Selector (“.class”)** | `implemented` | [specification](http://api.jquery.com/class-selector/)\n", "**:contains() Selector** | `TODO` | [specification](http://api.jquery.com/contains-selector/)\n", "**Descendant Selector (“ancestor descendant”)** | `implemented` | [specification](http://api.jquery.com/descendant-selector/)\n", "**:disabled Selector** | `implemented` | [specification](http://api.jquery.com/disabled-selector/)\n", "**Element Selector (“element”)** | `implemented` | [specification](http://api.jquery.com/element-selector/)\n", "**:empty Selector** | `implemented` | [specification](http://api.jquery.com/empty-selector/)\n", "**:enabled Selector** | `implemented` | [specification](http://api.jquery.com/enabled-selector/)\n", "**:eq() Selector** | `TODO` | [specification](http://api.jquery.com/eq-selector/)\n", "**:even Selector** | `implemented` | [specification](http://api.jquery.com/even-selector/)\n", "**:file Selector** | `implemented` | [specification](http://api.jquery.com/file-selector/)\n", "**:first-child Selector** | `TODO` | [specification](http://api.jquery.com/first-child-selector/)\n", "**:first-of-type Selector** | `TODO` | [specification](http://api.jquery.com/first-of-type-selector/)\n", "**:first Selector** | `TODO` | [specification](http://api.jquery.com/first-selector/)\n", "**:focus Selector** | `not possible` | [specification](http://api.jquery.com/focus-selector/)\n", "**:gt() Selector** | `TODO` | [specification](http://api.jquery.com/gt-selector/)\n", "**Has Attribute Selector [name]()** | `implemented` | [specification](http://api.jquery.com/has-attribute-selector/)\n", "**:has() Selector** | `TODO` | [specification](http://api.jquery.com/has-selector/)\n", "**:header Selector** | `TODO` | [specification](http://api.jquery.com/header-selector/)\n", "**:hidden Selector** | `implemented` | [specification](http://api.jquery.com/hidden-selector/)\n", "**ID Selector (“#id”)** | `implemented` | [specification](http://api.jquery.com/id-selector/)\n", "**:image Selector** | `implemented` | [specification](http://api.jquery.com/image-selector/)\n", "**:input Selector** | `implemented` | [specification](http://api.jquery.com/input-selector/)\n", "**:lang() Selector** | `TODO` | [specification](http://api.jquery.com/lang-selector/)\n", "**:last-child Selector** | `TODO` | [specification](http://api.jquery.com/last-child-selector/)\n", "**:last-of-type Selector** | `TODO` | [specification](http://api.jquery.com/last-of-type-selector/)\n", "**:last Selector** | `TODO` | [specification](http://api.jquery.com/last-selector/)\n", "**:lt() Selector** | `TODO` | [specification](http://api.jquery.com/lt-selector/)\n", "**Multiple Attribute Selector [name=”value”]([name2=”value2″])** | `implemented` | [specification](http://api.jquery.com/multiple-attribute-selector/)\n", "**Multiple Selector (“selector1, selector2, selectorN”)** | `TODO` | [specification](http://api.jquery.com/multiple-selector/)\n", "**Next Adjacent Selector (“prev + next”)** | `TODO` | [specification](http://api.jquery.com/next-adjacent-selector/)\n", "**Next Siblings Selector (“prev ~ siblings”)** | `TODO` | [specification](http://api.jquery.com/next-siblings-selector/)\n", "**:not() Selector** | `TODO` | [specification](http://api.jquery.com/not-selector/)\n", "**:nth-child() Selector** | `TODO` | [specification](http://api.jquery.com/nth-child-selector/)\n", "**:nth-last-child() Selector** | `TODO` | [specification](http://api.jquery.com/nth-last-child-selector/)\n", "**:nth-last-of-type() Selector** | `TODO` | [specification](http://api.jquery.com/nth-last-of-type-selector/)\n", "**:nth-of-type() Selector** | `TODO` | [specification](http://api.jquery.com/nth-of-type-selector/)\n", "**:odd Selector** | `implemented` | [specification](http://api.jquery.com/odd-selector/)\n", "**:only-child Selector** | `TODO` | [specification](http://api.jquery.com/only-child-selector/)\n", "**:only-of-type Selector** | `TODO` | [specification](http://api.jquery.com/only-of-type-selector/)\n", "**:parent Selector** | `TODO` | [specification](http://api.jquery.com/parent-selector/)\n", "**:password Selector** | `implemented` | [specification](http://api.jquery.com/password-selector/)\n", "**:radio Selector** | `implemented` | [specification](http://api.jquery.com/radio-selector/)\n", "**:reset Selector** | `not possible` | [specification](http://api.jquery.com/reset-selector/)\n", "**:root Selector** | `useless[1]` | [specification](http://api.jquery.com/root-selector/)\n", "**:selected Selector** | `implemented` | [specification](http://api.jquery.com/selected-selector/)\n", "**:submit Selector** | `implemented` | [specification](http://api.jquery.com/submit-selector/)\n", "**:target Selector** | `not possible` | [specification](http://api.jquery.com/target-selector/)\n", "**:text Selector** | `implemented` | [specification](http://api.jquery.com/text-selector/)\n", "**:visible Selector** | `not possible` | [specification](http://api.jquery.com/visible-selector/)\n", "\n", "\n", "[1]() :root Selector seems to be useless in our case because with the HTML parser the root is always the html node.\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": ".NET (F#)", "language": "F#", "name": ".net-fsharp" }, "language_info": { "file_extension": ".fs", "mimetype": "text/x-fsharp", "name": "polyglot-notebook", "pygments_lexer": "fsharp" }, "polyglot_notebook": { "kernelInfo": { "defaultKernelName": "fsharp", "items": [ { "aliases": [], "languageName": "fsharp", "name": "fsharp" } ] } } }, "nbformat": 4, "nbformat_minor": 2 }