Files
TPSchedule/mobile/lib/features/school/school_exam_adapter.dart
T

92 lines
2.8 KiB
Dart

import 'dart:convert';
import 'package:html/parser.dart' as html;
import '../../domain/exam_schedule.dart';
class SchoolExamAdapter {
static ExamSchedule extract(String content) {
try {
if (utf8.encode(content).length > 2 * 1024 * 1024) {
throw const FormatException();
}
final document = html.parse(content);
final selected = document.querySelector('#xqbh option[selected]');
final term = selected?.attributes['value'];
final table = document.querySelector('#sample-table-1');
const headers = [
'id',
'序号',
'学号',
'姓名',
'课程代码',
'课程名称',
'考核方式',
'考生编号',
'考场顺序号',
'考场',
'座位号',
'考试时间',
];
if (selected == null ||
term == null ||
table == null ||
!RegExp(r'^\d+$').hasMatch(term)) {
throw const FormatException();
}
final rows = table.querySelectorAll('tr');
if (rows.isEmpty || rows.first.children.length != headers.length) {
throw const FormatException();
}
for (var i = 0; i < headers.length; i++) {
if (rows.first.children[i].text.trim() != headers[i]) {
throw const FormatException();
}
}
final records = <ExamRecord>[];
var explicitlyEmpty = false;
for (final row in rows.skip(1)) {
// DataTables can insert a single explicit no-data placeholder.
if (row.children.length == 1 &&
row.children.first.attributes['colspan'] == '12' &&
const [
'没有数据',
'暂无数据',
'无数据',
'No data available in table',
].contains(row.text.trim())) {
explicitlyEmpty = true;
continue;
}
if (row.children.length != 12 ||
row.querySelector('script,style') != null) {
throw const FormatException();
}
final cells = row.children.map((c) => c.text.trim()).toList();
records.add(
ExamRecord(
code: cells[4],
name: cells[5],
assessment: cells[6],
candidate: cells[7],
sequence: cells[8],
room: cells[9],
seat: cells[10],
time: cells[11],
),
);
}
if (records.isEmpty && !explicitlyEmpty) throw const FormatException();
return ExamSchedule.fromJson(
ExamSchedule(
semesterLabel: selected.text.trim(),
termId: term,
records: records,
).toJson(),
);
} catch (_) {
throw const FormatException('未识别到完整的考试查询表,已有考试信息保持不变。');
}
}
}