code wiki / _hdl_build / nx_html_table.nx
nx_html_table.nx source
↩ module page · 109 lines · 4590 B
1// nx_html_table.nx -- SOVEREIGN HTML TABLE extractor: the reusable "access it properly" rung for ingesting
2// tabular data from any science body's HTML (CIAAW, NIST, BIPM, ...) WITHOUT grep -- it parses the table
3// STRUCTURE (rows x cells) and decodes entities through the proven nx_html_decode_entities. Composes the
4// existing sovereign HTML stack; hardware-rung-up (fetch[TLS]->tokenize->THIS->typed-extract->seg_store).
5//
6// API (reusable):
7// ht_find_open(html, n, pos, tag) -> index of next "<tag" (case-insens, tag-boundary checked), -1
8// ht_next_row(html, n, pos, rs_out, re_out) -> content [rs,re) of the next <tr>; returns next-pos or -1
9// ht_cell(html, rs, re, col, out, cap) -> extract the col-th <td> cell as clean text (tags stripped,
10// entities decoded). 1 found / 0 absent.
11// No JS, no 3rd-party parser. license_tier: ORIGINAL
12import "nx_syscalls.nx"
13import "nx_html_entities.nx"
14
15func ht_lc(b: u8) -> u8 { if b >= (65 as u8) { if b <= (90 as u8) { return (b + 32) as u8 } } return b }
16
17// does html[p..] begin with "<tag" (case-insensitive) followed by a tag boundary?
18func ht_is_open(html: *u8, n: i64, p: i64, tag: *u8) -> i64 {
19 if p >= n { return 0 }
20 if html[p] != (60 as u8) { return 0 } // '<'
21 var i: i64 = 0
22 while tag[i] != (0 as u8) {
23 if p + 1 + i >= n { return 0 }
24 if ht_lc(html[p + 1 + i]) != ht_lc(tag[i]) { return 0 }
25 i = i + 1
26 }
27 if p + 1 + i >= n { return 0 }
28 let c: u8 = html[p + 1 + i]
29 if c == (32 as u8) { return 1 }
30 if c == (62 as u8) { return 1 } // '>'
31 if c == (9 as u8) { return 1 } // tab
32 if c == (10 as u8) { return 1 } // newline
33 if c == (13 as u8) { return 1 }
34 if c == (47 as u8) { return 1 } // '/'
35 return 0
36}
37func ht_find_open(html: *u8, n: i64, pos: i64, tag: *u8) -> i64 {
38 var p: i64 = pos
39 while p < n { if ht_is_open(html, n, p, tag) == 1 { return p } p = p + 1 }
40 return 0 - 1
41}
42// find "</tag>" at/after pos (case-insensitive); return its start index or -1.
43func ht_find_close(html: *u8, n: i64, pos: i64, tag: *u8) -> i64 {
44 var p: i64 = pos
45 while p + 1 < n {
46 if html[p] == (60 as u8) { if html[p+1] == (47 as u8) { // "</"
47 var i: i64 = 0; var ok: i64 = 1
48 while tag[i] != (0 as u8) {
49 if p + 2 + i >= n { ok = 0; break }
50 if ht_lc(html[p+2+i]) != ht_lc(tag[i]) { ok = 0; break }
51 i = i + 1
52 }
53 if ok == 1 { return p }
54 } }
55 p = p + 1
56 }
57 return 0 - 1
58}
59// index just after the next '>' from pos.
60func ht_after_gt(html: *u8, n: i64, pos: i64) -> i64 {
61 var p: i64 = pos
62 while p < n { if html[p] == (62 as u8) { return p + 1 } p = p + 1 }
63 return n
64}
65
66// clean text of html[a..b): strip tags, decode entities, into out. returns length.
67func ht_text(html: *u8, a: i64, b: i64, out: *u8, cap: i64) -> i64 {
68 let tmp: *u8 = sys_mmap(cap + 16)
69 var k: i64 = 0; var p: i64 = a
70 while p < b {
71 if html[p] == (60 as u8) { // '<' -> skip the whole tag
72 while p < b { if html[p] == (62 as u8) { p = p + 1; break } p = p + 1 }
73 } else { if k < cap - 1 { tmp[k] = html[p]; k = k + 1 } p = p + 1 }
74 }
75 tmp[k] = 0 as u8
76 let m: i64 = nx_html_decode_entities(tmp, 0, k, out, cap)
77 out[m] = 0 as u8
78 return m
79}
80
81// extract the col-th <td> cell of row [rs,re) as clean text. 1/0.
82func ht_cell(html: *u8, rs: i64, re: i64, col: i64, out: *u8, cap: i64) -> i64 {
83 var p: i64 = rs; var c: i64 = 0
84 while p < re {
85 let td: i64 = ht_find_open(html, re, p, "td" as *u8)
86 if td < 0 { return 0 }
87 let cs: i64 = ht_after_gt(html, re, td)
88 let tdc: i64 = ht_find_close(html, re, cs, "td" as *u8)
89 var ce: i64 = re
90 if tdc >= 0 { ce = tdc }
91 if c == col { ht_text(html, cs, ce, out, cap); return 1 }
92 c = c + 1
93 p = ce + 1
94 }
95 return 0
96}
97
98// content [rs,re) of the next <tr> at/after pos. returns next scan pos, or -1 if none.
99func ht_next_row(html: *u8, n: i64, pos: i64, rs_out: *i64, re_out: *i64) -> i64 {
100 let tr: i64 = ht_find_open(html, n, pos, "tr" as *u8)
101 if tr < 0 { return 0 - 1 }
102 let cs: i64 = ht_after_gt(html, n, tr)
103 let trc: i64 = ht_find_close(html, n, cs, "tr" as *u8)
104 var ce: i64 = n
105 if trc >= 0 { ce = trc }
106 rs_out[0] = cs
107 re_out[0] = ce
108 return ce + 1
109}