I am using Graphviz to create a graph with nodes that are HTML-like labels. My dot file:
digraph 0 {
center = true
charset = "UTF-8"
overlap = false
splines = true
landscape = false
id = "0"
label = "Graph Example"
labelloc = "t"
node [shape = none width = 0 height = 0 margin = 0 fontcolor = blue ]
0 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "0" >Node 0</TD>
</TR>
<TR>
<TD CELLSPACING = "0" CELLPADDING = "0" >
<TABLE BORDER = "0" CELLSPACING = "1" CELLBORDER = "0" CELLPADDING = "0" >
<TR>
<TD PORT = "4"> </TD>
<TD PORT = "1"> </TD>
<TD PORT = "2"> </TD>
<TD PORT = "3"> </TD>
<TD PORT = "6"> </TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE> > ]
4 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "4" >Node 1</TD>
</TR>
<TR>
<TD CELLSPACING = "0" CELLPADDING = "0" >
<TABLE BORDER = "0" CELLSPACING = "1" CELLBORDER = "0" CELLPADDING = "0" >
<TR>
<TD PORT = "6"> </TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE> > ]
6 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "6" >Node 6</TD>
</TR>
</TABLE> > ]
1 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "1">Node 1</TD>
</TR>
<TR>
<TD CELLSPACING = "0" CELLPADDING = "0" >
<TABLE BORDER = "0" CELLSPACING = "1" CELLBORDER = "0" CELLPADDING = "0" >
<TR>
<TD PORT = "4"> </TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE> > ]
2 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "2">Node 2</TD>
</TR>
<TR>
<TD CELLSPACING = "0" CELLPADDING = "0" >
<TABLE BORDER = "0" CELLSPACING = "1" CELLBORDER = "0" CELLPADDING = "0" >
<TR>
<TD PORT = "4"> </TD>
<TD PORT = "5"> </TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE> > ]
5 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "5" >Node 5</TD>
</TR>
</TABLE> > ]
3 [ label = <
<TABLE BORDER = "0" CELLBORDER = "1" CELLSPACING = "0" CELLPADDING = "5" ALIGN = "CENTER" BGCOLOR = "white" COLOR = "black" >
<TR>
<TD PORT = "3" >Node 3</TD>
</TR>
<TR>
<TD CELLSPACING = "0" CELLPADDING = "0" >
<TABLE BORDER = "0" CELLSPACING = "1" CELLBORDER = "0" CELLPADDING = "0" >
<TR>
<TD PORT = "5"> </TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE> > ]
1:4:s -> 4:4:n
2:4:s -> 4:4:n
2:5:s -> 5:5:n
0:1:s -> 1:1:n
0:2:s -> 2:2:n
0:3:s -> 3:3:n
0:6:s -> 6:6:n
4:6:s -> 6:6:n
3:5:s -> 5:5:n
0:4:s -> 4:4:n
edge [color = red constraint = false ]
1:1 -> 4:4
1:1 -> 3:3
}
And I am using ports to define where on the node I want to connect with other nodes. Attached the image generated by dot.
I would like to have the edges drawn as polylines instead of curved arcs. I tried to modify the splines attribute for the graph but it does not work, in fact from the graphviz documentation I found this: "The value ortho specifies edges should be routed as polylines of axis-aligned segments. Currently, the routing does not handle ports or, in dot, edge labels."
Can you help in finding a solution to have polylines (or better looking edges) using ports?
Thanks.
simply change:
splines = true
to
splines = polyline
did the trick for me
result
Related
If one row is checked if($isset->has('test')) returns all rows.
I only want to save the marked rows.
My view file:
<tbody>
#foreach($match->homeTeam->players as $player)
<tr>
<th scope="row">{{$player->id}}</th>
<td class = "col-md-6" name = "player[]" value = "{{$player->id}}">{{$player->name}} {{$player->surname}}</td>
<td align="center" class= "col-md-2"><input class="form-check-input" type="checkbox" name="test" value="{{$player->id}}"></td>
<td class = "col-md-2"><input name="minutes[]" class="form-control"></td>
<td class = "col-md-2"><input name="goals[]" class="form-control"></td>
</tr>
#endforeach
</tbody>
Controller:
public function storeMatchFacts(Match $match, Request $request, Match_fact $match_fact, Player $player)
{
$home_team_players=$match->homeTeam->players;
if($isset->has('test')) {
foreach ( $home_team_players as $k => $p ) {
$data[] = [
'match_id' => $match->id,
'player_id' => $player->id,
'minutes' => $request['minutes'][$k],
'goals' => $request['goals'][$k]
];
}
dd($data);
} else {
dd('error');
}
I'm testing a plugin for dataTables called SearchPane, it works fine, but when i filter the table using the pane, the values keep stuck, not reflecting the values from the filtered table.
What i need is: after click on some value from the searchPane filter, the filter update values based on values of (filtered) updated table.
The documentation says something about it but not explain how apply it.
searchPane Documentation
The documentation have this information:
API - When the data in the table is updated, you'll want the search
panes to reflect this updated data - which can be done with the
searchPanes.rebuild() method - e.g.:
var table = $('#example').DataTable( {
searchPane: true
} );
table.row.add( ... ).draw();
table.searchPanes.rebuild();
but i don't know how to apply this in a working example.
my code:
$('#example').DataTable( {
searchPane: true
} )
<link href="https://cdn.datatables.net/1.10.11/css/jquery.dataTables.min.css" rel="stylesheet"/>
<link href="https://cdn.datatables.net/plug-ins/preview/searchPane/dataTables.searchPane.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/plug-ins/preview/searchPane/dataTables.searchPane.min.js"></script>
<div class="container">
<table cellpadding="0" cellspacing="0" border="0" class="dataTable" id="example">
<thead>
<tr>
<th>Rendering engine</th>
<th>Browser</th>
<th>Platform(s)</th>
<th>Engine version</th>
<th>CSS grade</th>
</tr>
</thead>
<tbody>
<tr>
<td>Trident</td>
<td>Internet
Explorer 4.0</td>
<td>Win 95+</td>
<td> 4</td>
<td>X</td>
</tr>
<tr>
<td>Trident</td>
<td>Internet
Explorer 5.0</td>
<td>Win 95+</td>
<td>5</td>
<td>C</td>
</tr>
<tr>
<td>Trident</td>
<td>Internet
Explorer 5.5</td>
<td>Win 95+</td>
<td>5.5</td>
<td>A</td>
</tr>
<tr>
<td>Trident</td>
<td>Internet
Explorer 6</td>
<td>Win 98+</td>
<td>6</td>
<td>A</td>
</tr>
<tr>
<td>Trident</td>
<td>Internet Explorer 7</td>
<td>Win XP SP2+</td>
<td>7</td>
<td>A</td>
</tr>
<tr>
<td>Trident</td>
<td>AOL browser (AOL desktop)</td>
<td>Win XP</td>
<td>6</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Firefox 1.0</td>
<td>Win 98+ / OSX.2+</td>
<td>1.7</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Firefox 1.5</td>
<td>Win 98+ / OSX.2+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Firefox 2.0</td>
<td>Win 98+ / OSX.2+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Firefox 3.0</td>
<td>Win 2k+ / OSX.3+</td>
<td>1.9</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Camino 1.0</td>
<td>OSX.2+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Camino 1.5</td>
<td>OSX.3+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Netscape 7.2</td>
<td>Win 95+ / Mac OS 8.6-9.2</td>
<td>1.7</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Netscape Browser 8</td>
<td>Win 98SE+</td>
<td>1.7</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Netscape Navigator 9</td>
<td>Win 98+ / OSX.2+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.0</td>
<td>Win 95+ / OSX.1+</td>
<td>1</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.1</td>
<td>Win 95+ / OSX.1+</td>
<td>1.1</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.2</td>
<td>Win 95+ / OSX.1+</td>
<td>1.2</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.3</td>
<td>Win 95+ / OSX.1+</td>
<td>1.3</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.4</td>
<td>Win 95+ / OSX.1+</td>
<td>1.4</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.5</td>
<td>Win 95+ / OSX.1+</td>
<td>1.5</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.6</td>
<td>Win 95+ / OSX.1+</td>
<td>1.6</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.7</td>
<td>Win 98+ / OSX.1+</td>
<td>1.7</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Mozilla 1.8</td>
<td>Win 98+ / OSX.1+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Seamonkey 1.1</td>
<td>Win 98+ / OSX.2+</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Gecko</td>
<td>Epiphany 2.20</td>
<td>Gnome</td>
<td>1.8</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>Safari 1.2</td>
<td>OSX.3</td>
<td>125.5</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>Safari 1.3</td>
<td>OSX.3</td>
<td>312.8</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>Safari 2.0</td>
<td>OSX.4+</td>
<td>419.3</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>Safari 3.0</td>
<td>OSX.4+</td>
<td>522.1</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>OmniWeb 5.5</td>
<td>OSX.4+</td>
<td>420</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>iPod Touch / iPhone</td>
<td>iPod</td>
<td>420.1</td>
<td>A</td>
</tr>
<tr>
<td>Webkit</td>
<td>S60</td>
<td>S60</td>
<td>413</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 7.0</td>
<td>Win 95+ / OSX.1+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 7.5</td>
<td>Win 95+ / OSX.2+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 8.0</td>
<td>Win 95+ / OSX.2+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 8.5</td>
<td>Win 95+ / OSX.2+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 9.0</td>
<td>Win 95+ / OSX.3+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 9.2</td>
<td>Win 88+ / OSX.3+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera 9.5</td>
<td>Win 88+ / OSX.3+</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Opera for Wii</td>
<td>Wii</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Nokia N800</td>
<td>N800</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Presto</td>
<td>Nintendo DS browser</td>
<td>Nintendo DS</td>
<td>8.5</td>
<td>C/A<sup>1</sup></td>
</tr>
<tr>
<td>KHTML</td>
<td>Konqureror 3.1</td>
<td>KDE 3.1</td>
<td>3.1</td>
<td>C</td>
</tr>
<tr>
<td>KHTML</td>
<td>Konqureror 3.3</td>
<td>KDE 3.3</td>
<td>3.3</td>
<td>A</td>
</tr>
<tr>
<td>KHTML</td>
<td>Konqureror 3.5</td>
<td>KDE 3.5</td>
<td>3.5</td>
<td>A</td>
</tr>
<tr>
<td>Tasman</td>
<td>Internet Explorer 4.5</td>
<td>Mac OS 8-9</td>
<td>-</td>
<td>X</td>
</tr>
<tr>
<td>Tasman</td>
<td>Internet Explorer 5.1</td>
<td>Mac OS 7.6-9</td>
<td>1</td>
<td>C</td>
</tr>
<tr>
<td>Tasman</td>
<td>Internet Explorer 5.2</td>
<td>Mac OS 8-X</td>
<td>1</td>
<td>C</td>
</tr>
<tr>
<td>Misc</td>
<td>NetFront 3.1</td>
<td>Embedded devices</td>
<td>-</td>
<td>C</td>
</tr>
<tr>
<td>Misc</td>
<td>NetFront 3.4</td>
<td>Embedded devices</td>
<td>-</td>
<td>A</td>
</tr>
<tr>
<td>Misc</td>
<td>Dillo 0.8</td>
<td>Embedded devices</td>
<td>-</td>
<td>X</td>
</tr>
<tr>
<td>Misc</td>
<td>Links</td>
<td>Text only</td>
<td>-</td>
<td>X</td>
</tr>
<tr>
<td>Misc</td>
<td>Lynx</td>
<td>Text only</td>
<td>-</td>
<td>X</td>
</tr>
<tr>
<td>Misc</td>
<td>IE Mobile</td>
<td>Windows Mobile 6</td>
<td>-</td>
<td>C</td>
</tr>
<tr>
<td>Misc</td>
<td>PSP browser</td>
<td>PSP</td>
<td>-</td>
<td>C</td>
</tr>
<tr>
<td>Other browsers</td>
<td>All others</td>
<td>-</td>
<td>-</td>
<td>U</td>
</tr>
</tbody>
</table>
</div>
table.row.add( ... ).draw();
table.searchPanes.rebuild();
remove above lines.
if u wanna use this with server side edit the "dataTables.searchPane.min.js" file as below.
var $jscomp = $jscomp || {}; $jscomp.scope = {}; $jscomp.findInternal = function (a, e, c) { a instanceof String && (a = String(a)); for (var g = a.length, d = 0; d < g; d++) { var l = a[d]; if (e.call(c, l, d, a)) return { i: d, v: l } } return { i: -1, v: void 0 } }; $jscomp.ASSUME_ES5 = !1; $jscomp.ASSUME_NO_NATIVE_MAP = !1; $jscomp.ASSUME_NO_NATIVE_SET = !1; $jscomp.defineProperty = $jscomp.ASSUME_ES5 || "function" == typeof Object.defineProperties ? Object.defineProperty : function (a, e, c) { a != Array.prototype && a != Object.prototype && (a[e] = c.value) };
$jscomp.getGlobal = function (a) { return "undefined" != typeof window && window === a ? a : "undefined" != typeof global && null != global ? global : a }; $jscomp.global = $jscomp.getGlobal(this); $jscomp.polyfill = function (a, e, c, g) { if (e) { c = $jscomp.global; a = a.split("."); for (g = 0; g < a.length - 1; g++) { var d = a[g]; d in c || (c[d] = {}); c = c[d] } a = a[a.length - 1]; g = c[a]; e = e(g); e != g && null != e && $jscomp.defineProperty(c, a, { configurable: !0, writable: !0, value: e }) } };
$jscomp.polyfill("Array.prototype.find", function (a) { return a ? a : function (a, c) { return $jscomp.findInternal(this, a, c).v } }, "es6-impl", "es3");
(function (a) { "function" === typeof define && define.amd ? define(["jquery", "datatables.net"], function (e) { return a(e, window, document) }) : "object" === typeof exports ? module.exports = function (e, c) { e || (e = window); c && c.fn.dataTable || (c = require("datatables.net")(e, c).$); return a(c, e, e.document) } : a(jQuery, window, document) })(function (a, e, c, g) {
function d(b, h) {
var f = this; b = new l.Api(b); this.classes = a.extend(!0, {}, d.classes); this.dom = { container: a("<div/>").addClass(this.classes.container) }; this.c = a.extend(!0, {}, d.defaults,
h); this.s = { dt: b }; b.settings()[0].searchPane = this; b.columns(this.c.columns).eq(0).each(function (a) { f._pane(a) }); a(this.dom.container).on("click", "li", function () { f._toggle(this) }).on("click", "button." + this.classes.clear, function () { f._clear(a(this).closest("div." + f.classes.pane.container)) }); this._attach()
} var l = a.fn.dataTable; a.extend(d.prototype, {
rebuild: function () { var a = this; this.s.dt.columns(this.c.columns).eq(0).each(function (b) { a._pane(b) }) }, _attach: function () {
var b = this.c.container, b = "function" ===
typeof b ? b(this.s.dt) : b; "prepend" === this.c.insert ? a(this.dom.container).prependTo(b) : a(this.dom.container).appendTo(b)
}, _binData: function (a) { var b = {}; a.each(function (a) { a && (b[a] ? b[a]++ : b[a] = 1) }); return b }, _clear: function (a) { var b = this.classes, f = b.item.selected; a.find("li." + f).removeClass(f); a.removeClass(b.pane.active); this.s.dt.column(a.data("column")).search("").draw() }, _pane: function (b) {
var h = this.classes, f = h.item, h = h.pane, c = this.s.dt.column(b), e = a("<ul/>"), d = this._binData(c.data().flatten());
if (!(this._variance(d) < this.c.threshold)) {
for (var g = c.search(), g = g ? g.substr(1, g.length - 2).split("|") : [], m = c.data().unique().sort().toArray(), k = 0, l = m.length; k < l; k++)if (m[k]) { var n = a("<li/>").html('<span class="' + f.label + '">' + m[k] + "</span>").data("filter", m[k]).append(a("<span/>").addClass(f.count).html(d[m[k]])); if (g.length) { var p = m[k].replace ? a.fn.dataTable.util.escapeRegex(m[k]) : m[k]; -1 !== a.inArray(p, g) && n.addClass(f.selected) } e.append(n) } f = a("<div/>").data("column", b).addClass(h.container).addClass(g.length ?
h.active : "").append(a('<button type="button">×</button>').addClass(this.classes.clear)).append(a("<div/>").addClass(h.title).html(a(c.header()).text())).append(a("<div/>").addClass(h.scroller).append(e)); h = this.dom.container; c = h.children().map(function () { if (a(this).data("column") == b) return this }); c.length ? c.replaceWith(f) : a(h).append(f)
}
}, _toggle: function (b) {
var c = this.classes, f = c.item.selected, e = this.s.dt; b = a(b); var d = b.closest("div." + c.pane.container); b.toggleClass(f, !b.hasClass(f)); b = d.find("li." +
f); 0 === b.length ? (d.removeClass(c.pane.active), e.column(d.data("column")).search("").draw()) : (d.addClass(c.pane.active), e.column(d.data("column")).search(a.map(b, function (b) { b = a(b).data("filter").toString(); return a.fn.dataTable.util.escapeRegex(b) }).join("|"), !0, !1).draw())
}, _variance: function (b) { b = a.map(b, function (a, b) { return a }); for (var c = b.length, f = 0, d = 0, e = c; d < e; d++)f += b[d]; for (var f = f / c, g = 0, d = 0, e = c; d < e; d++)g += Math.pow(f - b[d], 2); return g / (c - 1) }
}); d.classes = {
container: "dt-searchPanes", clear: "clear",
pane: { active: "filtering", container: "pane", title: "title", scroller: "scroller" }, item: { selected: "selected", label: "label", count: "count" }
}; d.defaults = { container: function (a) { return a.table().container() }, columns: g, insert: "prepend", threshold: .5 }; d.version = "0.0.1"; a.fn.dataTable.SearchPanes = d; a.fn.DataTable.SearchPanes = d; l.Api.register("searchPanes.rebuild()", function () { return this.iterator("table", function (a) { a.searchPane && a.searchPane.rebuild() }) }); a(c).on("init.dt", function (b, c, e) {
"dt" === b.namespace && (b =
c.oInit.searchPane, e = l.defaults.searchPane, b || e) && (e = a.extend({}, b, e), !1 !== b && new d(c, e))
})
});
Here's the table structure:
<table class="tb-stock tb-option">
<tr>
<th class="bgc2">col1</th>
<th class="bgc2">col2</th>
<th class="bgc2">col3</th>
</tr>
<tr class="alt-row">
<th class="">2018/1/29</th>
<td class="">0.11</td>
<td class=" b-b">0.50</td>
</tr>
<tr class="alt-row">
<th class="">2018/1/30</th>
<td class="">0.22</td>
<td class=" b-b">0.55</td>
</tr>
</table>
I want to get all the elements below "tr" (including "th" and "td")
How can I use linq to achieve this ?
Problems locate at "..tr.Elements("td|th").."
code:
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(ms, Encoding.UTF8);
List<List<string>> table =
doc.DocumentNode.SelectSingleNode("//table[#class='tb-stock tb-option']")
.Descendants("tr")
.Skip(1)
.Where(tr => tr.Elements("th").Count() >= 1)
.Select(tr => tr.Elements("td|th").Select(td => td.InnerText).ToList())
.ToList();
You can use the following code for extracting inner texts of td or th elements I test it in my local the output is :
2018/1/29
0.11
0.50
2018/1/30
0.22
0.55
You can filter the elements in line :
// both td and th
.Where(node => "td|th".Contains(node.Name))
// only td
.Where(node => "td".Contains(node.Name))
The working code is :
HtmlDocument doc = new HtmlDocument();
doc.Load("test.html", Encoding.UTF8);
List<string> table =
doc.DocumentNode.SelectSingleNode("//table[#class='tb-stock tb-option']")
.Descendants("tr")
.Skip(1)
.Where(tr => tr.Elements("th").Count() >= 1)
.SelectMany(tr => tr.ChildNodes)
.Where(node => "td|th".Contains(node.Name))
.Select(node => node.InnerText)
.ToList();
foreach (var str in table)
{
Console.WriteLine(str);
}
I have the following HTML code and need to determine the index of "Number of Strings" using the <span> id. I'm using Nokogiri to parse the HTML and get the row.
doc = Nokogiri::parse(myfile.html)
table = doc.xpath("//span[#id='NumStrs']/../../..")
row = table.xpath["tr[1]"]
Here is the HTML:
<tr>
<th id ="langframe">
<span id="cabinet">
Cabinet</span>
</th>
<th id ="langbb1">
<span id="bb1">
BB1</span>
</th>
<th id ="langbb2">
<span id="bb2">
BB2</span>
</th>
<th id ="langtemp">
<span id="Temp">
Temperature</span>
</th>
<th id="langstrs">
<span id="StringsPresent">
Strings Present</span>
</th>
<th id="langmstrQty">
<span id="NumStrs">
Number of Strings</span>
</th>
</tr>
I'd do it using Ruby's with_index combined with a select:
require 'nokogiri' # => true
doc = Nokogiri::HTML(<<EOT)
<tr>
<th id ="langframe">
<span id="cabinet">
Cabinet</span>
</th>
<th id ="langbb1">
<span id="bb1">
BB1</span>
</th>
<th id ="langbb2">
<span id="bb2">
BB2</span>
</th>
<th id ="langtemp">
<span id="Temp">
Temperature</span>
</th>
<th id="langstrs">
<span id="StringsPresent">
Strings Present</span>
</th>
<th id="langmstrQty">
<span id="NumStrs">
Number of Strings</span>
</th>
</tr>
EOT
th_idx = doc.search('th').to_enum.with_index.select { |th, idx| th.text['Number of Strings'] }.first
That returns:
th_idx
# => [#(Element:0x3fe72d83cd3c {
# name = "th",
# attributes = [
# #(Attr:0x3fe72d4440f4 { name = "id", value = "langmstrQty" })],
# children = [
# #(Text "\n"),
# #(Element:0x3fe72d43c3e0 {
# name = "span",
# attributes = [
# #(Attr:0x3fe72d439b04 { name = "id", value = "NumStrs" })],
# children = [ #(Text "\nNumber of Strings")]
# }),
# #(Text "\n")]
# }),
# 5]
The index is:
th_idx.last # => 5
Once you have th_idx, you can easily access parent or child nodes to find out about its surroundings:
th_node = th_idx.first
th_node['id'] # => "langmstrQty"
th_node.at('span')
# => #(Element:0x3fd5110286d8 {
# name = "span",
# attributes = [
# #(Attr:0x3fd511021b6c { name = "id", value = "NumStrs" })],
# children = [ #(Text "\nNumber of Strings")]
# })
th_node.at('span')['id'] # => "NumStrs"
with_index adds a 0-based index to each element passed to it. to_enum is required because search returns a NodeSet, which isn't an enumerator so to_enum returns that.
If you want a 1-based index use with_index(1).
Got it working, not sure if this is the efficient way to do it.. but it works
header = table.xpath("tr[1]")
value = header.xpath("//span[#id='#{id}']").text
index = header.search('th//text()').collect {|text| text.to_s.strip}.reject(&:empty?).index(value)+1
I'm working on creating a datatable that has a drill down (row details) sub datatable as per the requirement. I was able to create the sub datatable when using drill down (row details) approach, but finding it hard to expand all of these rows that have drill down associated while loading the table. Here is the code I have and it works and expands all drill down rows on the current paginated table., but when clicking on the next pagination (number or page), the rows shows as expand (you know you can see the 'minus' (close) icon image) but no sub datatable. As far as I understood, its because, when I'm trying to simulate a click on the 'img' attribute associated for a drill down row, its being applied successfully for the current rows in the current page, but for the rest, which are not in the dom, the script says that the sub datatable is undefined. Any ideas or suggestions around this would help me a lot..
Below is the code snippet -
Table HTML source code -
<table id="mastertable" class="table table-striped table-bordered table-hover dataTable" aria-describedby="sample-table-2_info">
<thead>
<tr role="row">
<!-- <th class="sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Domain: activate to sort column ascending" style="width: 255px;"></th> -->
<th class="sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Domain: activate to sort column ascending" style="width: 25%;">Project Name</th>
<th class="sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Price: activate to sort column ascending" style="width: 10%;">Status</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Clicks: activate to sort column ascending" style="width: 10%;">Start Date</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Clicks: activate to sort column ascending" style="width: 10%;">End Date</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Clicks: activate to sort column ascending" style="width: 10%;">FCS Date</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Clicks: activate to sort column ascending" style="width: 10%;">Project Phase</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" aria-label="Clicks: activate to sort column ascending" style="width: 15%;">Defects</th>
</tr>
</thead>
<tbody role="alert" aria-live="polite" aria-relevant="all">
<tr>
<td class=" ">
<img src="/tester/theme/v_1_0/app-images/details_open.png" masterProject="master-ROORKELA"/>
ROORKELA <font color="black">(System Project)</font>
// THIS IS THE SUB DATATABLE HIDDEN IN DIV AND THE ID OF THE DIV IS STORED IN THE IMG ATTRIBUTE ABOVE UNDER THE 'masterProject' attribute - [masterProject="master-ROORKELA"]
<div class="hide" id="master-ROORKELA">
<table id="subProjects-table" class="table table-striped table-bordered table-hover subTable" aria-describedby="sample-table-2_info">
<thead>
<tr role="row">
<th class="sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 255px;">Project Name</th>
<th class="sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 186px;">Status</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 203px;">Start Date</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 203px;">End Date</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 203px;">Targetted Date</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 203px;">Project Phase</th>
<th class="hidden-480 sorting" role="columnheader" tabindex="0" aria-controls="sample-table-2" rowspan="1" colspan="1" style="width: 203px;">Defects</th>
</tr>
</thead>
<tbody role="alert" aria-live="polite" aria-relevant="all">
<tr>
<td class=" " style="width: 26%;text-align:center;vertical-align: middle;">
Sirish
</td>
<td class="hidden-480 " style="width: 10%;">
<span class="label label-sm label-warning">Minor Impact</span>
</td>
<td class=" " style="width: 10%;">Feb 12 2013</td>
<td class="hidden-480 " style="width: 10%;">Nov 12 2013</td>
<td class=" " style="width: 10%;">Jan 16 2014</td>
<td class=" " style="width: 10%;">EFT</td>
<td class=" " style="width: 15%;">
22 defects
</tr>
</tbody>
</table>
</div>
</td>
<td class="hidden-480 ">
<span class="label label-sm label-warning">Minor Impact</span>
</td>
<td class=" ">Feb 12 2013</td>
<td class="hidden-480 ">Nov 12 2013</td>
<td class=" ">Jan 16 2014</td>
<td class=" ">TESTING</td>
<td class=" ">22 defects
</tr>
</tbody>
</table>
Defining the initial table -
var oTable = $('#mastertable').dataTable( {
"aLengthMenu": [[5,10, 25, 50, 100 , -1], [5,10, 25, 50, 100, "All"]],
"iDisplayLength" : 10,
"aoColumnDefs": [
{"sWidth": "25%", "aTargets": [ 0 ] },
{"sWidth": "10%", "aTargets": [ 1 ] },
{"sWidth": "10%", "aTargets": [ 2 ] },
{"sWidth": "10%", "aTargets": [ 3 ] },
{"sWidth": "10%", "aTargets": [ 4 ] },
{"sWidth": "10%", "aTargets": [ 5 ] },
{"sWidth": "15%", "aTargets": [ 6 ] },
{"sClass": "align-left" , "aTargets": [ 0,1,4, 2,3,5,6] }
],
"sDom": '<"row"<"col-sm-4"l><"col-sm-6"f><"col-sm-1 saveas_div"T><"col-sm-1 filtering_div"C>r>t<"row"<"col-sm-6"i><"col-sm-6"p>>',
"oTableTools": {
"aButtons": [
{
"sExtends": 'csv',
"sButtonText":'Export as CSV',
"mColumns":"visible"
}
]
},
"aoColumns": [
{ "bSortable": true },
null, null, null,null, null,
{ "bSortable": true }
],
"bStateSave": true,
"fnStateSave": function (oSettings, oData) {
localStorage.setItem( 'DataTables_'+window.location.pathname, JSON.stringify(oData) );
},
"fnStateLoad": function (oSettings) {
return JSON.parse( localStorage.getItem('DataTables_'+window.location.pathname) );
}
});
Associating click events on the 'img' attributes in the table -
oTable.$('td').each( function () {
$(this).on('click','img', function () {
var nTr = $(this).parents('tr')[0];
if ( oTable.fnIsOpen(nTr) )
{
/* This row is already open - close it */
this.src = "${pageContext.request.contextPath}/theme/v_1_0/app-images/details_open.png";
oTable.fnClose( nTr );
}
else
{
/* Open this row */
this.src = "${pageContext.request.contextPath}/theme/v_1_0/app-images/details_close.png";
var masterProject = $(this).attr("masterProject");
var html = $("#"+masterProject).html();
console.log(html); // THIS IS WHERE I SEE AS UNDEFINED FOR HIDDEN TR ELEMENTS WHICH ARE HIDDEN DURING PAGINATION
oTable.fnOpen(nTr, html, 'details');
}
} );
$(this).find('img').trigger('click'); // THIS IS WHERE I"M SIMULATING CLICK EVENT TO EXPAND ALL ROWS WHILE LOADING PAGE BY DEFAULT.
});
I tried using the - fnDrawCallback method to simulate the click events, but its giving me weird results, meaning rows are expanded on alternate pages like 1,3,5 but on consecutive pages.
Sorry for this monologue, as am just trying to explain the detail of the problem.
Please pass on your valuable suggestions or solutions..
Many thanks,
Sirish.
So I added functionality on button to collapse all and expand all child rows. that will work with pagination, search and
<script>
function format ( d ) {
// `d` is the original data object for the row
return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">'+
'<tr>'+
'<td>Full CallStack:</td>'+
'<td style="text-align:left;">'+d.call_stack+'</td>'+
'</tr>'+
'</table>';
}
$(document).ready(function() {
var isCollapse = 1;
var visited_cehck = 0;
var table = $('#example').DataTable( {
"aaData": $Json_data,
"aoColumns": [
{ "sTitle": "col1", "mData": "col1" },
{ "sTitle": "col2", "mData": "col2" },
{ "sTitle": "col3", "mData": "col3" },
{ "sTitle": "col4", "mData": "col4" },
{ "sTitle": "col5", "mData": "col5" },
{
"class": 'details-control',
"orderable": false,
"data": null,
"defaultContent": ''
}
]
} );
//This function gets the length of the row and collapse and
//expend all the rows depending on the current state of the row:
function collapse_exand_rows(){
var table_length = $('#example tbody tr').length;
for (var i = 0; i < table_length; i++) {
var tr = $('.details-control').parents('tr').eq(i);
var row = table.row( tr );
if(!tr.hasClass('visited_child') || visited_cehck != 1){
if ( isCollapse === 1 ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Open this row
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
}
}
}
//This event handles click for on each child row to show and hide rows.
$('#example tbody').on('click', 'td.details-control', function () {
var tr = $(this).parents('tr');
var row = table.row( tr );
visited_cehck = 1;
tr.addClass('visited_child');
if ( row.child.isShown() ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Open this row
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
} );
//This event handles navigation bar below the report to show and hide all the visible rows
$('.dataTables_paginate').bind('click', '.details-control', function(event) {
if(visited_cehck === 1){
return false;
}
collapse_exand_rows();
});
//This event handles collapse expand button click to show and hide all the visible rows
$('#collapse_expand').on('click', function(event) {
visited_cehck = 0;
if(isCollapse === 1){
$('#collapse_expand').text('Collapse All');
isCollapse = 0;
}
else{
$('#collapse_expand').text('Expand All');
isCollapse = 1;
}
collapse_exand_rows();
});
//This event handles dropdown to show and hide all the visible rows
$('select').on('change', function (event) {
collapse_exand_rows();
});
$("thead > tr", '#example').click(function(event) {
collapse_exand_rows();
})
$(':input').change(function(event) {
collapse_exand_rows();
});
});
</script>
do something like this:
var table_length = $("#mastertable tr").length;
var paginate_button = $('.paginate_button');
for(var i = 0; i< table_length; i++){
var tr = $('#mastertable tbody td.details-control').eq(i).parents('tr');
var row = table.row(tr);
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
if you have pagination :
isCollapse === 0
paginate_button.on('click',function(){
table_length = $("#example tr").length;
if ( isCollapse === 1 ) {
for(var i = 0; i< table_length; i++){
var tr = $('#example tbody td.details-control').eq(i).parents('tr');
var row = table.row(tr);
row.child.hide();
tr.removeClass('shown');
}
}
else {
// Open this row
for(var i = 0; i< table_length; i++){
var tr = $('#example tbody td.details-control').eq(i).parents('tr');
var row = table.row(tr);
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
}
});