<b>Measurement Table: MTF vs. Image Height</b> <br><br> <!-- open measurement table --> <table cellspacing=3D"0" align=3D"left" id=3D"ITableDataItems" class=3D"CTa= bleDataItems"> <!-- begin table caption --> <tbody><tr id=3D"ITRDataCaption" class=3D"CTRDataCaption"> <td id=3D"ITDCaptionBlank" class=3D"CTDCaptionBlank"></td> <td align=3D"center" colspan=3D"5" id=3D"ITDDataCaption" class=3D"CTDDataCa= ption">Image Height (mm)</td> </tr> <tr id=3D"ITRDataCaption" class=3D"CTRDataCaption"> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">MTF</td> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">0.42800</td> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">0.29960</td> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">-0.00114</td> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">-0.29960</td> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">-0.42800</td> <td id=3D"ITDDataCaption" class=3D"CTDDataCaption">Legend</td> </tr> <!-- end table caption --> <!-- begin measurement data --> <tr id=3D"ITRDataItem" class=3D"CTRDataItem"> <td id=3D"ITDEven" class=3D"CTDDataItem">Tan 100(lp/mm)</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.599</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.677</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.668</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.703</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.645</td> <td colspan=3D"1" id=3D"ITDLegend" class=3D"CTDLegend"><font color=3D"ff000= 0">— — —</font></td> </tr> <tr id=3D"ITRDataItem" class=3D"CTRDataItem"> <td id=3D"ITDEven" class=3D"CTDDataItem">Sag 100(lp/mm)</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.558</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.659</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.673</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.688</td> <td id=3D"ITDEven" class=3D"CTDDataItem">0.642</td> <td colspan=3D"1" id=3D"ITDLegend" class=3D"CTDLegend"><font color=3D"ff000= 0">————</font></td> </tr> <!-- end measurement data --> <!-- close measurement table -->// 解析Measurement Table: MTF vs. Image Height int TriopticsParser::parseMeasurementTable4MTFvsImageHeight(const QDomElement& preElement, tagMTFvsImageHeightTable& table) { QString title = preElement.text(); if (title == ("Measurement Table: MTF vs. Image Height")) { table.title = title; } return 0; }
时间: 2025-07-02 09:19:02 浏览: 6
<think>我们有一个HTML片段,它描述了一个测量表格(Measurement Table: MTF vs. ImageHeight)。我们需要解析这个表格,提取表头和表格数据。表格结构分析:-表格有一个标题行(caption),其中第一行是“Image Height(mm)”,横跨5列(实际上有5个数据列)。-第二行是表头,第一个单元格是“MTF”,然后依次是5个图像高度的数值,最后一个单元格是“Legend”。-接下来是数据行,每行第一个单元格是描述(如“Tan100(lp/mm)”),然后有5个数据单元格,最后一个单元格是图例(例如一个红色的横线)。我们需要解析这个表格,并将数据存储到结构体`tagMTFvsImageHeightTable`中(假设这个结构体已经定义)。步骤:1.定位到表格元素。根据前面的代码,我们是通过`preElement`来定位的(注意:在HTML中,表格前面有一个`<b>`标签包含的标题,然后是一个`<br>`,然后是表格)。2.由于在函数中,我们传入的是`preElement`(即包含标题文本的元素),我们需要找到紧随其后的表格。但是注意,函数参数是`preElement`,它可能是包含标题文本的节点(比如一个`<b>`元素),然后表格是它的下一个兄弟节点?或者我们需要通过其他方式定位表格。然而,在给定的函数中,我们直接通过`preElement`来获取标题文本,然后判断标题文本是否为“Measurement Table: MTF vs. ImageHeight”。但是,表格并不在`preElement`内,而是紧随其后。因此,我们需要调整思路:首先,`preElement`可能是包含标题的节点(比如一个`b`标签),然后表格是它的下一个兄弟节点(注意:在HTML中,标题和表格之间有两个`<br>`标签,所以我们需要跳过这些文本节点和注释节点,找到下一个元素节点)。所以,我们需要:-首先,确认`preElement`的文本内容是否匹配标题。-然后,找到`preElement`的下一个兄弟元素节点,即表格(`<table>`)。但是,在给定的HTML片段中,表格的id为"ITableDataItems",我们可以利用这个id来查找,但更通用的方法是找到下一个`table`元素。函数设计:int TriopticsParser::parseMeasurementTable4MTFvsImageHeight(constQDomElement&preElement, tagMTFvsImageHeightTable& table)步骤:1.从`preElement`中获取文本,并判断是否包含目标标题(注意:可能包含多余空格,需要清理)。2.如果匹配,则开始查找表格。表格可能是`preElement`的下一个兄弟元素(注意:DOM树中,`preElement`后面的节点可能是文本节点、注释节点、元素节点等,我们需要跳过非元素节点,直到找到第一个`table`元素)。3.如果找到表格,开始解析表格。解析表格:-表格的第一行(tr)是表头的一部分,我们忽略第一行(因为它只是“ImageHeight (mm)”),因为它横跨5列,但实际数据行表头在第二行。-第二行:第一个单元格是“MTF”,然后5个图像高度值,最后一个单元格是“Legend”。-从第三行开始是数据行(注意:在HTML片段中,注释说第三行开始是测量数据)。具体解析:-表头(第二行)的第二个到第六个单元格(td)是图像高度值(注意:第一个单元格是“MTF”,然后5个数值,最后一个是“Legend”)。-数据行:每行第一个单元格是描述(如“Tan100(lp/mm)”),然后5个数据,最后一个单元格是图例(我们可能不需要图例,但需要根据需求决定)。假设结构体`tagMTFvsImageHeightTable`定义如下(假设):structtagMTFvsImageHeightTable {QStringtitle;QList<QString> imageHeights;//存储5个图像高度值(字符串形式,也可以转换为double)QList<QList<QString>>data;//每一行数据(除了第一列和最后一列),或者我们可以定义更详细的结构//或者,我们可以按列存储,每一行是一个记录structDataRow {QStringtype;//如 "Tan100(lp/mm)"QList<double>values;//5个数值QString legend; //图例,可能不需要};QList<DataRow>rows;};由于我们不知道结构体的确切定义,我将根据常见的需求设计解析过程,并假设结构体可以存储这些数据。代码步骤:1.清理标题文本,判断是否为目标表格。2.定位表格元素:从preElement开始,遍历后续兄弟节点,直到找到一个元素节点且标签名为"table"。3.获取表格的所有行(tr)。4.跳过前两行(因为前两行是标题行)。5.从第三行开始解析数据行。注意:表格可能有多个tbody?但在这个例子中,表格是直接包含tr的。代码实现:注意:由于给定的HTML片段中有一些属性(如id、class)和注释,我们不需要依赖这些,而是依赖结构。我们将按照以下步骤编码:1.验证标题2.找到表格3.解析表头(第二行)中的图像高度值4.解析数据行下面给出具体代码:</think># 解析 MTF vs. Image Height 测量表格
根据您提供的 HTML 表格结构和解析函数框架,我将实现完整的 `parseMeasurementTable4MTFvsImageHeight` 函数来解析 MTF vs. Image Height 测量数据表。
## 完整解析代码实现
```cpp
#include <QDomElement>
#include <QDebug>
// 定义数据结构
struct MTFDataRow {
QString type; // 测量类型 (如 "Tan 100(lp/mm)")
QVector<double> values; // 各位置测量值
QString legend; // 图例标记
};
struct tagMTFvsImageHeightTable {
QString title; // 表格标题
QVector<double> imageHeights; // 图像高度值 (mm)
QVector<MTFDataRow> dataRows; // 测量数据行
QString legendTitle; // 图例标题
};
int TriopticsParser::parseMeasurementTable4MTFvsImageHeight(const QDomElement& preElement,
tagMTFvsImageHeightTable& table)
{
// 1. 解析标题
QString title = preElement.text().trimmed();
if (title != "Measurement Table: MTF vs. Image Height") {
qWarning() << "Unexpected table title:" << title;
return -1; // 不是目标表格
}
table.title = title;
// 2. 定位表格元素
QDomElement tableElement = preElement.nextSiblingElement("table");
if (tableElement.isNull()) {
qWarning() << "No table element found after title";
return -2;
}
// 3. 解析表头行 (Image Height 值)
QDomElement headerRow = tableElement.firstChildElement("tr");
while (!headerRow.isNull()) {
if (headerRow.attribute("id") == "ITRDataCaption") {
// 找到包含图像高度值的行
QDomElement headerCell = headerRow.firstChildElement("td");
int colIndex = 0;
while (!headerCell.isNull()) {
// 跳过空白单元格
if (headerCell.attribute("id") == "ITDCaptionBlank") {
headerCell = headerCell.nextSiblingElement("td");
continue;
}
// 解析图像高度值
if (colIndex > 0) { // 跳过第一个单元格(标题)
QString text = headerCell.text().trimmed();
bool ok;
double height = text.toDouble(&ok);
if (ok) {
table.imageHeights.append(height);
} else {
qWarning() << "Invalid image height value:" << text;
}
}
headerCell = headerCell.nextSiblingElement("td");
colIndex++;
}
break; // 找到并处理完表头后跳出循环
}
headerRow = headerRow.nextSiblingElement("tr");
}
// 4. 解析数据行
QDomElement dataRow = tableElement.firstChildElement("tr");
while (!dataRow.isNull()) {
if (dataRow.attribute("id") == "ITRDataItem") {
MTFDataRow rowData;
QDomElement dataCell = dataRow.firstChildElement("td");
int colIndex = 0;
while (!dataCell.isNull()) {
QString text = dataCell.text().trimmed();
if (colIndex == 0) {
// 第一列:测量类型
rowData.type = text;
}
else if (dataCell.attribute("id") == "ITDLegend") {
// 图例列
rowData.legend = text;
}
else {
// 数据值列
bool ok;
double value = text.toDouble(&ok);
if (ok) {
rowData.values.append(value);
} else {
qWarning() << "Invalid MTF value:" << text;
}
}
dataCell = dataCell.nextSiblingElement("td");
colIndex++;
}
// 添加到表格数据
if (!rowData.type.isEmpty() && !rowData.values.isEmpty()) {
table.dataRows.append(rowData);
}
}
dataRow = dataRow.nextSiblingElement("tr");
}
// 5. 解析图例标题
QDomElement legendRow = tableElement.firstChildElement("tr");
while (!legendRow.isNull()) {
if (legendRow.attribute("id") == "ITRDataCaption") {
QDomElement legendCell = legendRow.firstChildElement("td");
while (!legendCell.isNull()) {
if (legendCell.attribute("id") == "ITDDataCaption" &&
legendCell.text().trimmed() == "Legend") {
table.legendTitle = "Legend";
break;
}
legendCell = legendCell.nextSiblingElement("td");
}
}
legendRow = legendRow.nextSiblingElement("tr");
}
return table.dataRows.isEmpty() ? -3 : 0; // 返回0表示成功
}
// 使用示例
void printMTFTable(const tagMTFvsImageHeightTable& table) {
qDebug() << "Table Title:" << table.title;
qDebug() << "Image Heights:" << table.imageHeights;
qDebug() << "Legend Title:" << table.legendTitle;
for (const MTFDataRow& row : table.dataRows) {
qDebug() << "\nMeasurement Type:" << row.type;
qDebug() << "Values:" << row.values;
qDebug() << "Legend:" << row.legend;
}
}
int main() {
// 假设已经加载了DOM文档
QDomDocument doc;
// ... 加载文档的代码 ...
// 查找包含标题的元素
QDomElement titleElement;
QDomNodeList bElements = doc.elementsByTagName("b");
for (int i = 0; i < bElements.count(); i++) {
QDomElement el = bElements.at(i).toElement();
if (!el.isNull() && el.text().contains("Measurement Table: MTF vs. Image Height")) {
titleElement = el;
break;
}
}
if (titleElement.isNull()) {
qDebug() << "Title element not found";
return 1;
}
// 解析表格
tagMTFvsImageHeightTable mtfTable;
TriopticsParser parser;
int result = parser.parseMeasurementTable4MTFvsImageHeight(titleElement, mtfTable);
if (result == 0) {
printMTFTable(mtfTable);
} else {
qDebug() << "Failed to parse table, error code:" << result;
}
return 0;
}
```
## 代码解析
### 1. 数据结构定义
```cpp
struct MTFDataRow {
QString type; // 测量类型
QVector<double> values; // 各位置测量值
QString legend; // 图例标记
};
struct tagMTFvsImageHeightTable {
QString title; // 表格标题
QVector<double> imageHeights; // 图像高度值
QVector<MTFDataRow> dataRows; // 测量数据行
QString legendTitle; // 图例标题
};
```
- `MTFDataRow` 存储单行测量数据
- `tagMTFvsImageHeightTable` 存储整个表格数据
### 2. 解析流程
#### 步骤1: 验证标题
```cpp
QString title = preElement.text().trimmed();
if (title != "Measurement Table: MTF vs. Image Height") {
return -1;
}
```
确保处理的是正确的表格
#### 步骤2: 定位表格元素
```cpp
QDomElement tableElement = preElement.nextSiblingElement("table");
```
找到标题元素后面的表格元素
#### 步骤3: 解析图像高度值
```cpp
while (!headerRow.isNull()) {
if (headerRow.attribute("id") == "ITRDataCaption") {
// 解析高度值...
}
headerRow = headerRow.nextSiblingElement("tr");
}
```
从表头行提取图像高度值(0.42800, 0.29960等)
#### 步骤4: 解析测量数据行
```cpp
while (!dataRow.isNull()) {
if (dataRow.attribute("id") == "ITRDataItem") {
MTFDataRow rowData;
// 解析类型、值和图例...
table.dataRows.append(rowData);
}
dataRow = dataRow.nextSiblingElement("tr");
}
```
提取每行测量数据(Tan/Sag 100(lp/mm)及其对应值)
#### 步骤5: 解析图例标题
```cpp
while (!legendRow.isNull()) {
if (legendRow.attribute("id") == "ITRDataCaption") {
// 查找"Legend"单元格...
}
legendRow = legendRow.nextSiblingElement("tr");
}
```
定位并存储图例标题
### 3. 错误处理
函数返回状态码:
- `0`: 成功
- `-1`: 标题不匹配
- `-2`: 表格元素未找到
- `-3`: 无有效数据行
## 高级功能:数据验证和处理
### 1. 数据有效性检查
```cpp
// 检查值数量是否匹配
if (rowData.values.size() != table.imageHeights.size()) {
qWarning() << "Value count mismatch for row:" << rowData.type;
}
```
### 2. 处理HTML实体
```cpp
QString decodeHtmlEntities(const QString& input) {
QString result = input;
result.replace("&", "&");
result.replace("<", "<");
result.replace(">", ">");
result.replace(""", "\"");
result.replace("'", "'");
result.replace("—", "—"); // 长破折号
return result;
}
// 在解析图例时使用
rowData.legend = decodeHtmlEntities(text);
```
### 3. 处理颜色信息
```cpp
QString extractColor(const QDomElement& element) {
if (element.hasAttribute("color")) {
return element.attribute("color");
}
// 检查font子元素
QDomElement font = element.firstChildElement("font");
if (!font.isNull() && font.hasAttribute("color")) {
return font.attribute("color");
}
return QString();
}
// 在解析图例时
rowData.legendColor = extractColor(dataCell);
```
## 使用场景示例
### 生成CSV报告
```cpp
void exportToCsv(const tagMTFvsImageHeightTable& table, const QString& filename) {
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
QTextStream out(&file);
// 写入标题
out << "Table Title:," << table.title << "\n\n";
// 写入图像高度标题
out << "Measurement Type,";
for (double height : table.imageHeights) {
out << QString::number(height, 'f', 5) << ",";
}
out << "Legend\n";
// 写入数据
for (const MTFDataRow& row : table.dataRows) {
out << row.type << ",";
for (double value : row.values) {
out << QString::number(value, 'f', 3) << ",";
}
out << row.legend << "\n";
}
file.close();
}
```
### 生成图表数据
```cpp
QMap<QString, QVector<QPointF>> prepareChartData(const tagMTFvsImageHeightTable& table) {
QMap<QString, QVector<QPointF>> seriesData;
for (const MTFDataRow& row : table.dataRows) {
QVector<QPointF> points;
for (int i = 0; i < row.values.size(); i++) {
points.append(QPointF(table.imageHeights[i], row.values[i]));
}
seriesData.insert(row.type, points);
}
return seriesData;
}
```
## 错误处理和边界情况
### 1. 处理缺失的列
```cpp
// 在解析数据行时
if (rowData.values.size() < table.imageHeights.size()) {
// 填充缺失值
for (int i = rowData.values.size(); i < table.imageHeights.size(); i++) {
rowData.values.append(0.0); // 或特殊值如 -999.0
}
}
```
### 2. 处理无效数值
```cpp
// 在转换数值时
double value = text.toDouble(&ok);
if (!ok) {
// 尝试清理字符串
QString cleaned = text;
cleaned.remove(QRegExp("[^0-9.-]"));
value = cleaned.toDouble(&ok);
if (!ok) {
value = std::numeric_limits<double>::quiet_NaN();
}
}
```
### 3. 处理表格结构变化
```cpp
// 使用更宽松的选择器
if (headerRow.attribute("class") == "CTRDataCaption" ||
headerRow.text().contains("Image Height")) {
// 处理表头
}
```
阅读全文
相关推荐




<html><head><meta http-equiv="Content-Type" content="text/html; charset=
=iso-8859-1">
<title>Trioptics Certificate</title>
<base href="file:///C:/Program%20Files%20(x86)/TRIOPTICS%20GmbH/MTF-LAB%2=
05/Certificates/"></base></head>
<body id="IBodyCert" class="CBodyCert">
ImageMaster - Certificate
Company : ******
Operator : ******
Time/Date : 13:30:33 June 12, 2025
Sample ID : ******
Measure Program : MTF vs. Field
Temperature : 20°C
Measured with : TRIOPTICS - MT=
F-LAB - Vers. 5.16.1
Instrument S/N : 09-113-0519
Comments : SN215U0540
Measurement Parameter: MTF vs. Image Height
Setup Type : Object Infinite / Image Finite
EFL (Collimator): 50 mm
Wavelength : 940 nm (NIR)
EFL (Sample) : 1.5550 mm
F-Number : 2.0000
Object Angle : -0.0198 °
Focus Position : 85.8471
Sample Azimuth : 0.0 °
Measurement Graph: MTF vs. Image Height
<right>
</right>
Measurement Table: MTF vs. Image Height
Image Height (mm)
MTF
0.42800
0.29960
-0.00114
-0.29960
-0.42800
Legend
Tan 100(lp/mm)
0.599
0.677
0.668
0.703
0.645
— — —
Sag 100(lp/mm)
0.558
0.659
0.673
0.688
0.642
————
Measurement Parameter: MTF vs. Object Angle
Setup Type : Object Infinite / Image Finite
EFL (Collimator): 50 mm
Wavelength : 940 nm (NIR)
EFL (Sample) : 1.5550 mm
F-Number : 2.0000
Object Angle : -0.0198 °
Focus Position : 85.8471
Sample Azimuth : 0.0 °
Measurement Graph: MTF vs. Object Angle
<right>
</right>
Measurement Table: MTF vs. Object Angle
Object Angle (?
MTF
-15.33590
-10.72937
0.00072
10.77662
15.40352
Legend
Tan 100(lp/mm)
0.599
0.677
0.668
0.703
0.645
— — —
Sag 100(lp/mm)
0.558
0.659
0.673
0.688
0.642
————
</body></html> 解析这个

Measurement Parameter: MTF vs. Image Height Setup Type : Object Infinite / Image Finite EFL (Collimator): 50 mm Wavelength : 940 nm (NIR) EFL (Sample) : 1.5550 mm F-Number : 2.0000 Object Angle : -0.0198 ° Focus Position : 85.8471 Sample Azimuth : 0.0 °
Measurement Graph: MTF vs. Image Height
<right>
Measurement Table: MTF vs. Image Height
Measurement Parameter: MTF vs. Object Angle Setup Type : Object Infinite / Image Finite EFL (Collimator): 50 mm Wavelength : 940 nm (NIR) EFL (Sample) : 1.5550 mm F-Number : 2.0000 Object Angle : -0.0198 ° Focus Position : 85.8471 Sample Azimuth : 0.0 °
Measurement Graph: MTF vs. Object Angle
<right>
Measurement Table: MTF vs. Object Angle

Measurement Graph: MTF vs. Image Height
<right>
</right>
qt解析
用qt解析
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><meta content="IE=5.0000" =
http-equiv="X-UA-Compatible"/>
<TITLE>Trioptics Certificate</TITLE>
<meta http-equiv="Content-Type" content="text/html; =
charset=windows-1252"/>
<meta name="GENERATOR" content="MSHTML 11.00.9600.18538"/></HEAD>
<BODY class="CBodyCert" id="IBodyCert">
ImageMaster -
Certificate
Company : Sunex
=
Operator : TH
=
Time/Date : 20:29:14 June 14, 2025
=
Sample ID : 0
=
Measure Program : 3D Tilt Corrected Through Focus
=
Temperature : 20°C
=
Measured with : TRIOPTICS - =
MTF-LAB - Vers. 5.13.2
=
Instrument S/N : 09-113-0259
=
Comments : AMT5
=
// 修复HTML文档使其符合XML规范:
QString TriopticsParser::preprocessHtmlForXml(const QString & html)
{
QString result = html;
// 1. 修复字符集声明
result.replace("charset=\n=iso-8859-1", "charset=\"iso-8859-1\"");
// 2. 转义URL中的&符号
result.replace(QRegularExpression("href=\"([^\"]*?)(?<!&|<|>|'|")&([^\"]*?)\""),
"href=\"\\1&\\2\"");
// 3. 修复自闭合标签
QStringList selfClosingTags = { "img", "br", "hr", "meta", "link" };
for (const QString& tag : selfClosingTags)
{
// 处理有属性的标签
result.replace(QRegularExpression(QString("<%1\\b([^>]*)>").arg(tag),
QRegularExpression::CaseInsensitiveOption),
QString("<%1\\1/>").arg(tag));
// 处理没有属性的标签
result.replace(QRegularExpression(QString("<%1\\s*>").arg(tag),
QRegularExpression::CaseInsensitiveOption),
QString("<%1/>").arg(tag));
}
// 4. 移除无效的结束标签
result.replace("", "");
// 5. 添加XML声明
if (!result.contains("<?xml"))
{
result.prepend("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
}
return result;
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><META content="IE=5.0000" http-equiv="X-UA-Compatible">
<TITLE>Trioptics Certificate</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<META name="GENERATOR" content="MSHTML 11.00.9600.18538"></HEAD>
<BODY class="CBodyCert" id="IBodyCert">
ImageMaster -
Certificate
Company : Sunexbool MhtParser::parse(const QByteArray &mhtData)
{
m_htmlContent.clear();
m_resources.clear();
// 查找 MIME 边界
static QRegularExpression boundaryRegex("boundary=\"([^\"]+)\"");
QRegularExpressionMatch match = boundaryRegex.match(mhtData);
if (!match.hasMatch()) {
qWarning() << "MHT boundary not found";
return false;
}
QString boundary = "--" + match.captured(1);
QList<QByteArray> parts = safeSplit(mhtData, boundary.toUtf8());
// 跳过第一个和最后一个部分(非内容部分)
for (int i = 1; i < parts.size() - 1; ++i) {
parseMimePart(parts[i].trimmed());
}
return !m_htmlContent.isEmpty();
}函数兼容解析这种的

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><meta content="IE=5.0000" =
http-equiv="X-UA-Compatible"/>
<TITLE>Trioptics Certificate</TITLE>
<meta http-equiv="Content-Type" content="text/html; =
charset=windows-1252"/>
<meta name="GENERATOR" content="MSHTML 11.00.9600.18538"/></HEAD>
<BODY class="CBodyCert" id="IBodyCert">
ImageMaster -
Certificate
Company : Sunex
=
Operator : TH
=
Time/Date : 20:29:14 June 14, 2025
=
Sample ID : 0
=
Measure Program : 3D Tilt Corrected Through Focus
=
Temperature : 20°C
=
Measured with : TRIOPTICS - =
MTF-LAB - Vers. 5.13.2
=
Instrument S/N : 09-113-0259
=
Comments : AMT5
=
// 修复HTML文档使其符合XML规范:
QString TriopticsParser::preprocessHtmlForXml(const QString & html)
{
QString result = html;
// 1. 修复字符集声明
result.replace("charset=\n=iso-8859-1", "charset=\"iso-8859-1\"");
// 2. 转义URL中的&符号
result.replace(QRegularExpression("href=\"([^\"]*?)(?<!&|<|>|'|")&([^\"]*?)\""),
"href=\"\\1&\\2\"");
// 3. 修复自闭合标签
QStringList selfClosingTags = { "img", "br", "hr", "meta", "link" };
for (const QString& tag : selfClosingTags)
{
// 处理有属性的标签
result.replace(QRegularExpression(QString("<%1\\b([^>]*)>").arg(tag),
QRegularExpression::CaseInsensitiveOption),
QString("<%1\\1/>").arg(tag));
// 处理没有属性的标签
result.replace(QRegularExpression(QString("<%1\\s*>").arg(tag),
QRegularExpression::CaseInsensitiveOption),
QString("<%1/>").arg(tag));
}
// 4. 移除无效的结束标签
result.replace("", "");
// 5. 添加XML声明
if (!result.contains("<?xml"))
{
result.prepend("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
}
return result;
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><META content="IE=5.0000" http-equiv="X-UA-Compatible">
<TITLE>Trioptics Certificate</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<META name="GENERATOR" content="MSHTML 11.00.9600.18538"></HEAD>
<BODY class="CBodyCert" id="IBodyCert">
ImageMaster -
Certificate
Company : Sunexbool MhtParser::parse(const QByteArray &mhtData)
{
m_htmlContent.clear();
m_resources.clear();
// 查找 MIME 边界
static QRegularExpression boundaryRegex("boundary=\"([^\"]+)\"");
QRegularExpressionMatch match = boundaryRegex.match(mhtData);
if (!match.hasMatch()) {
qWarning() << "MHT boundary not found";
return false;
}
QString boundary = "--" + match.captured(1);
QList<QByteArray> parts = safeSplit(mhtData, boundary.toUtf8());
// 跳过第一个和最后一个部分(非内容部分)
for (int i = 1; i < parts.size() - 1; ++i) {
parseMimePart(parts[i].trimmed());
}
return !m_htmlContent.isEmpty();
}函数兼容解析这种的
