文件目录自动生成工具--Dir Tree Noter

在编写代码readme文件时,展示目录结构通常是个繁琐的任务。DirTreeNoter(yardtea.cc)是一款实用的在线工具,能够帮助你轻松自动生成文件目录结构。只需将根目录拖入其指定区域,即可一键复制使用,极大地提高了工作效率。

文件目录自动生成工具–Dir Tree Noter

我们在为自己的代码编写readme文件的过程中,需要展示自己代码的目录结构,比如下面这种

image-20210123145354498

如果自己手动去完成比较麻烦,而且会产生遗漏,这里我们推荐使用自动生成工具,网址如下:

Dir Tree Noter (yardtea.cc)

http://dir.yardtea.cc/

我们只需要把根目录拖入下面的框中,就能得到文件目录结构,复制就可以使用。

image-20210123145600645

<think>我们将在当前目录下生成HTML报告,并在Windows系统下自动打开。上面的代码已经实现了这个功能,但是为了确保清晰,我再次说明:1.在脚本的最后,我们调用`save_and_open_html_report`函数,将HTML内容写入文件"awb_diff_report.html"(默认文件名),然后使用`webbrowser.open`打开该文件。2.由于在Windows系统中,`webbrowser.open`会使用默认浏览器打开本地文件(使用`file://`协议)。但是,请注意:上面的代码已经是一个完整的脚本,包括生成HTML报告和打开报告的功能。如果你需要修改报告保存的位置,可以在`save_and_open_html_report`函数中修改`filename`参数,或者传递不同的文件名。现在,我将提供完整的代码,但请注意,由于代码很长,我已经在上一个回答中提供了完整的代码。如果你需要再次查看,这里就是。但是,为了确保满足你的要求(在同目录下生成并自动打开),我们已经做到了。如果你想要修改报告文件名,可以修改`report_filename`变量(在`main`函数中),例如:report_filename= "my_report.html"如果运行中遇到任何问题,请检查:-是否有写入当前目录的权限-系统默认浏览器是否设置正确由于代码已经很长,这里不再重复提供完整代码,你可以直接使用上一个回答中的代码。如果还有问题,请告诉我。</think>我将为您提供一个完整的解决方案,在Python脚本同目录下生成带有颜色的HTML报告,并在Windows系统下自动打开该报告。以下是实现代码: ```python import sys import xml.etree.ElementTree as ET import re import os import subprocess import webbrowser from datetime import datetime import html import tempfile import platform # 初始化colorama from colorama import init, Fore, Style init(autoreset=True) class Color: """ANSI颜色代码""" RED = '\033[91m' YELLOW = '\033[93m' GREEN = '\033[92m' BLUE = '\033[94m' CYAN = '\033[96m' BOLD = '\033[1m' UNDERLINE = '\033[4m' RESET = '\033[0m' def colorize(text, color): """为文本添加颜色""" return f"{color}{text}{Color.RESET}" def find_all_ccmatrix_nodes(root): """查找所有 Awb_TblCCMatrix 开头的节点""" pattern = re.compile(r"Awb_TblCCMatrix_\w+_0") nodes = [] for node in root.iter(): tag = node.tag.split('}')[-1] # 移除命名空间 if pattern.match(tag): nodes.append((tag, node)) return nodes def is_numeric(value): """检查是否是数值类型(整数或浮点数)""" try: float(value) return True except (ValueError, TypeError): return False def parse_multi_value(text): """解析包含多个数值的文本""" if not text: return [] return [float(x) for x in text.split() if is_numeric(x)] def check_row_sum(values, tolerance=1e-3): """检查矩阵每行求和是否为1(允许一定误差)""" if len(values) != 9: return [] results = [] # 第一行: 0,1,2 row1_sum = sum(values[0:3]) results.append({ "row": 1, "values": values[0:3], "sum": row1_sum, "valid": abs(row1_sum - 1) <= tolerance }) # 第二行: 3,4,5 row2_sum = sum(values[3:6]) results.append({ "row": 2, "values": values[3:6], "sum": row2_sum, "valid": abs(row2_sum - 1) <= tolerance }) # 第三行: 6,7,8 row3_sum = sum(values[6:9]) results.append({ "row": 3, "values": values[6:9], "sum": row3_sum, "valid": abs(row3_sum - 1) <= tolerance }) return results def get_warning_level(diff, yellow_threshold=0.05, red_threshold=0.1): """根据差异值确定警告级别""" if diff > red_threshold: return "red" elif diff > yellow_threshold: return "yellow" return "none" def compare_multi_values(val1, val2, path, yellow_threshold=0.05, red_threshold=0.1): """比较多个数值的变化""" values1 = parse_multi_value(val1) values2 = parse_multi_value(val2) if not values1 or not values2 or len(values1) != len(values2): # 无法进行元素级比较,返回整体比较 return compare_text_value(val1, val2, path, yellow_threshold, red_threshold), [] changes = [] warnings = [] max_diff = 0.0 for i, (v1, v2) in enumerate(zip(values1, values2)): diff = v1 - v2 abs_diff = abs(diff) max_diff = max(max_diff, abs_diff) warning_level = get_warning_level(abs_diff, yellow_threshold, red_threshold) change = { "path": f"{path}[{i}]", "change": f"{v1:.6f} → {v2:.6f}", "type": "数值", "diff": abs_diff, "delta": diff, "warning_level": warning_level } changes.append(change) if warning_level != "none" and "ctemp" not in path.lower(): level_text = colorize("红色警告", Color.RED) if warning_level == "red" else colorize("黄色警告", Color.YELLOW) warnings.append(f"{level_text}: {path}[{i}] 变化 ({v1:.6f} → {v2:.6f}, 差值={abs_diff:.6f})") # 添加汇总行 summary_warning = get_warning_level(max_diff, yellow_threshold, red_threshold) changes.append({ "path": f"{path}/汇总", "change": f"最大差值: {max_diff:.6f}", "type": "汇总", "diff": max_diff, "warning_level": summary_warning }) if summary_warning != "none" and "ctemp" not in path.lower(): level_text = colorize("红色警告", Color.RED) if summary_warning == "red" else colorize("黄色警告", Color.YELLOW) warnings.append(f"{level_text}: {path} 最大变化 (最大差值={max_diff:.6f})") return changes, warnings def compare_text_value(val1, val2, path, yellow_threshold=0.05, red_threshold=0.1): """比较单个文本值""" changes = [] warnings = [] # 数值类型的变化检查 if is_numeric(val1) and is_numeric(val2): v1 = float(val1) v2 = float(val2) diff = abs(v1 - v2) delta = v1 - v2 change_type = "数值" warning_level = get_warning_level(diff, yellow_threshold, red_threshold) if warning_level != "none" and "ctemp" not in path.lower(): level_text = colorize("红色警告", Color.RED) if warning_level == "red" else colorize("黄色警告", Color.YELLOW) warnings.append(f"{level_text}: {path} 变化 ({v1:.6f} → {v2:.6f}, 差值={diff:.6f})") else: diff = 0 delta = 0 change_type = "非数值" warning_level = "none" changes.append({ "path": path, "change": f"{val1} → {val2}", "type": change_type, "diff": diff, "delta": delta, "warning_level": warning_level }) return changes, warnings def process_ccmatrix_node(node, path): """处理单个CCMatrix节点,检查矩阵行和""" results = [] for child in node.iter(): if child.text and "ccmatrix" in child.tag.lower(): values = parse_multi_value(child.text) if len(values) == 9: row_checks = check_row_sum(values) for check in row_checks: status = "✅" if check["valid"] else "❌" result = { "path": f"{path}/{child.tag}$row{check['row']}", "status": status, "values": check["values"], "sum": check["sum"], "valid": check["valid"] } results.append(result) return results def compare_nodes(n1, n2, path="", yellow_threshold=0.05, red_threshold=0.1): """比较两个节点的差异,忽略ctemp的警告但输出差异""" changes = [] warnings = [] row_checks = [] # 处理第一个节点的矩阵行和检查 row_checks.extend(process_ccmatrix_node(n1, f"{path}/基准值")) # 处理第二个节点的矩阵行和检查 row_checks.extend(process_ccmatrix_node(n2, f"{path}/新值")) # 比较属性 for attr in set(n1.attrib.keys()) | set(n2.attrib.keys()): val1 = n1.attrib.get(attr, "") val2 = n2.attrib.get(attr, "") if val1 != val2: # 数值类型的变化检查 if is_numeric(val1) and is_numeric(val2): v1 = float(val1) v2 = float(val2) diff = abs(v1 - v2) delta = v1 - v2 change_type = "数值" warning_level = get_warning_level(diff, yellow_threshold, red_threshold) if warning_level != "none" and "ctemp" not in attr.lower(): level_text = colorize("红色警告", Color.RED) if warning_level == "red" else colorize("黄色警告", Color.YELLOW) warnings.append(f"{level_text}: {path}@{attr} 变化 ({v1:.6f} → {v2:.6f}, 差值={diff:.6f})") else: diff = 0 delta = 0 change_type = "非数值" warning_level = "none" changes.append({ "path": f"{path}@{attr}", "change": f"{val1} → {val2}", "type": change_type, "diff": diff, "delta": delta, "warning_level": warning_level }) # 比较文本内容 text1 = (n1.text or "").strip() text2 = (n2.text or "").strip() if text1 != text2: # 检查是否是多个数值 values1 = text1.split() values2 = text2.split() if len(values1) > 1 and len(values2) > 1 and len(values1) == len(values2): # 处理多个数值的情况 multi_changes, multi_warnings = compare_multi_values( text1, text2, f"{path}$text", yellow_threshold, red_threshold ) changes.extend(multi_changes) warnings.extend(multi_warnings) else: # 处理单个值或无法比较的情况 single_changes, single_warnings = compare_text_value( text1, text2, f"{path}$text", yellow_threshold, red_threshold ) changes.extend(single_changes) warnings.extend(single_warnings) # 比较子节点 children1 = {child.tag: child for child in n1} children2 = {child.tag: child for child in n2} # 共同子节点比较 for tag in set(children1.keys()) | set(children2.keys()): if tag in children1 and tag in children2: child_changes, child_warnings, child_row_checks = compare_nodes( children1[tag], children2[tag], f"{path}{tag}/", yellow_threshold, red_threshold ) changes.extend(child_changes) warnings.extend(child_warnings) row_checks.extend(child_row_checks) elif tag in children2: # 新增子节点 changes.append({ "path": f"{path}+{tag}", "change": "[新增]", "type": "结构", "diff": 0, "delta": 0, "warning_level": "none" }) else: # 删除子节点 changes.append({ "path": f"{path}-{tag}", "change": "[删除]", "type": "结构", "diff": 0, "delta": 0, "warning_level": "none" }) return changes, warnings, row_checks def compare_ccmatrix_across_files(file1, file2, yellow_threshold=0.05, red_threshold=0.1): try: # 解析XML tree1 = ET.parse(file1) root1 = tree1.getroot() tree2 = ET.parse(file2) root2 = tree2.getroot() # 查找所有CCMatrix节点 nodes1 = find_all_ccmatrix_nodes(root1) nodes2 = find_all_ccmatrix_nodes(root2) # 按场景分组 scenes1 = {scene for scene, _ in nodes1} scenes2 = {scene for scene, _ in nodes2} all_scenes = sorted(scenes1 | scenes2) results = [] global_warnings = [] # 收集所有警告 global_row_checks = [] # 收集所有矩阵行和检查 # 对比每个场景 for scene in all_scenes: node1 = next((node for s, node in nodes1 if s == scene), None) node2 = next((node for s, node in nodes2 if s == scene), None) exists1 = node1 is not None exists2 = node2 is not None changes = [] warnings = [] row_checks = [] if exists1 and exists2: changes, warnings, row_checks = compare_nodes( node1, node2, f"{scene}/", yellow_threshold, red_threshold ) global_warnings.extend(warnings) global_row_checks.extend(row_checks) results.append({ "scene": scene, "exists_in_file1": exists1, "exists_in_file2": exists2, "changes": changes, "warnings": warnings, "row_checks": row_checks }) return results, global_warnings, global_row_checks except ET.ParseError as e: return None, [f"XML解析错误: {str(e)}"], [] except FileNotFoundError as e: return None, [f"文件未找到: {str(e)}"], [] except Exception as e: return None, [f"处理错误: {str(e)}"], [] def print_colored_header(text, width=80, color=Color.BLUE): """打印带颜色的标题""" padding = (width - len(text)) // 2 print(colorize("=" * width, Color.CYAN)) print(colorize(" " * padding + text + " " * padding, color + Color.BOLD)) print(colorize("=" * width, Color.CYAN)) def generate_html_report(results, global_warnings, global_row_checks, file1, file2, yellow_threshold, red_threshold): """生成HTML格式的报告""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # HTML模板 html_template = f""" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Awb_TblCCMatrix 参数对比报告</title> <style> body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; margin: 0; padding: 20px; background-color: #f5f5f5; }} .container {{ max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0,0,0,0.1); padding: 20px; }} .header {{ background: linear-gradient(135deg, #1e90ff, #00bfff); border-radius: 10px; padding: 30px; margin-bottom: 20px; text-align: center; color: white; }} h1 {{ margin-top: 0; font-size: 28px; text-shadow: 1px 1px 2px rgba(0,0,0,0.2); }} h2 {{ color: #1e90ff; border-bottom: 2px solid #1e90ff; padding-bottom: 8px; margin-top: 25px; }} .warning {{ padding: 15px; margin: 15px 0; border-radius: 8px; }} .warning-red {{ background-color: #ffebee; border-left: 5px solid #f44336; }} .warning-yellow {{ background-color: #fff8e1; border-left: 5px solid #ffc107; }} .scene {{ background-color: #ffffff; border-radius: 10px; padding: 20px; margin-bottom: 25px; border: 1px solid #e0e0e0; box-shadow: 0 2px 5px rgba(0,0,0,0.05); }} .scene-header {{ background-color: #e3f2fd; padding: 15px; border-radius: 8px; margin-bottom: 15px; }} .scene-title {{ font-size: 20px; color: #1565c0; margin: 0; }} .changes-table {{ width: 100%; border-collapse: collapse; margin: 15px 0; font-size: 14px; }} .changes-table th, .changes-table td {{ border: 1px solid #e0e0e0; padding: 10px; text-align: left; }} .changes-table th {{ background-color: #f1f8ff; font-weight: bold; color: #1976d2; }} .changes-table tr:nth-child(even) {{ background-color: #fafafa; }} .changes-table tr:hover {{ background-color: #f0f7ff; }} .red-warning {{ color: #d32f2f; font-weight: bold; }} .yellow-warning {{ color: #f57c00; font-weight: bold; }} .green-check {{ color: #388e3c; }} .red-check {{ color: #d32f2f; }} .ctemp-change {{ color: #1976d2; font-weight: bold; }} .summary-row {{ font-weight: bold; background-color: #e8f5e9 !important; }} .file-info {{ display: flex; justify-content: space-between; margin-top: 10px; flex-wrap: wrap; }} .file-info div {{ flex: 1; min-width: 300px; margin: 5px; }} .threshold-info {{ display: flex; justify-content: center; gap: 30px; margin-top: 10px; }} .threshold-box {{ padding: 8px 15px; border-radius: 5px; }} .yellow-threshold {{ background-color: #fff8e1; color: #f57c00; }} .red-threshold {{ background-color: #ffebee; color: #d32f2f; }} .footer {{ margin-top: 30px; text-align: center; color: #757575; font-size: 0.9em; padding-top: 15px; border-top: 1px solid #e0e0e0; }} .no-changes {{ text-align: center; padding: 20px; color: #388e3c; font-weight: bold; }} .matrix-fail {{ background-color: #ffebee; padding: 10px; border-radius: 5px; margin-top: 10px; }} .matrix-fail-values {{ font-family: monospace; font-size: 13px; }} </style> </head> <body> <div class="container"> <div class="header"> <h1>Awb_TblCCMatrix 参数对比报告</h1> <div class="file-info"> <div><strong>基准文件:</strong> {html.escape(file1)}</div> <div><strong>对比文件:</strong> {html.escape(file2)}</div> </div> <div class="threshold-info"> <div class="threshold-box yellow-threshold"><strong>黄色阈值:</strong> {yellow_threshold:.6f}</div> <div class="threshold-box red-threshold"><strong>红色阈值:</strong> {red_threshold:.6f}</div> </div> <p><strong>生成时间:</strong> {timestamp}</p> </div> """ # 添加全局警告 if global_warnings: html_template += "<h2>⚠️ 全局警告</h2>" for warning in global_warnings: # 提取警告文本并移除ANSI颜色代码 warning_text = re.sub(r'\033\[\d+m', '', warning) if "红色警告" in warning_text: html_template += f'<div class="warning warning-red">🔴 {html.escape(warning_text)}</div>' elif "黄色警告" in warning_text: html_template += f'<div class="warning warning-yellow">🟡 {html.escape(warning_text)}</div>' # 添加每个场景的详情 html_template += "<h2>📊 场景对比详情</h2>" for result in results: scene = result["scene"] exists1 = result["exists_in_file1"] exists2 = result["exists_in_file2"] changes = result["changes"] row_checks = result["row_checks"] # 场景状态指示器 status_icon = "✅" if exists1 and exists2 else "⚠️" html_template += f""" <div class="scene"> <div class="scene-header"> <h3 class="scene-title">{status_icon} 场景: {html.escape(scene)}</h3> <p>基准文件存在: <strong>{'是' if exists1 else '否'}</strong> | 对比文件存在: <strong>{'是' if exists2 else '否'}</strong></p> </div> """ if exists1 and exists2: if changes: html_template += "<h4>检测到变化:</h4>" html_template += '<table class="changes-table">' html_template += '<tr><th>路径</th><th>变化</th><th>类型</th><th>差值</th></tr>' for change in changes: path = change["path"] change_text = change["change"] change_type = change["type"] diff = change["diff"] # 确定CSS类 row_class = "" if "ctemp" in path.lower(): row_class = "ctemp-change" elif change["warning_level"] == "red": row_class = "red-warning" elif change["warning_level"] == "yellow": row_class = "yellow-warning" # 对于汇总行添加特殊样式 if "汇总" in path: row_class += " summary-row" # 格式化差值 diff_display = f"{diff:.6f}" if is_numeric(str(diff)) else "-" html_template += f'<tr class="{row_class}">' html_template += f'<td>{html.escape(path)}</td>' html_template += f'<td>{html.escape(change_text)}</td>' html_template += f'<td>{html.escape(change_type)}</td>' html_template += f'<td>{diff_display}</td>' html_template += '</tr>' html_template += '</table>' else: html_template += '<div class="no-changes">✅ 无变化</div>' # 添加矩阵行和检查 if row_checks: all_passed = all(check["valid"] for check in row_checks) if all_passed: html_template += '<p class="green-check">✅ 所有矩阵行和检查通过 (每行和≈1.000000)</p>' else: html_template += '<div class="matrix-fail">' html_template += '<p class="red-check">❌ 以下矩阵行和检查失败:</p>' html_template += '<ul>' for check in row_checks: if not check["valid"]: values = " ".join(f"{v:.6f}" for v in check["values"]) html_template += f'<li>{html.escape(check["path"])}: 和={check["sum"]:.6f} ≠ 1.000000</li>' html_template += f'<li class="matrix-fail-values">值: {values}</li>' html_template += '</ul>' html_template += '</div>' html_template += "</div>" # 关闭scene div # 添加页脚 html_template += f""" <div class="footer"> <p>报告生成时间: {timestamp}</p> <p>工具版本: AWB Diff Tool 1.0 | © {datetime.now().year}</p> </div> </div> <!-- 关闭container --> </body> </html> """ return html_template def save_and_open_html_report(html_content, filename="awb_diff_report.html"): """保存HTML报告并在浏览器中打开""" try: # 获取当前脚本所在目录 script_dir = os.path.dirname(os.path.abspath(__file__)) report_path = os.path.join(script_dir, filename) # 保存HTML文件 with open(report_path, "w", encoding="utf-8") as f: f.write(html_content) print(f"报告已保存到: {report_path}") # 在默认浏览器中打开报告 if platform.system() == 'Windows': # Windows系统使用特定方式确保路径正确 report_path = os.path.abspath(report_path) os.startfile(report_path) else: # 其他系统使用webbrowser webbrowser.open(f'file://{os.path.abspath(report_path)}') return True except Exception as e: print(f"保存或打开报告时出错: {str(e)}") return False def main(): if len(sys.argv) < 3: print("用法: python awb_diff.py <文件1.xml> <文件2.xml> [黄色阈值=0.05] [红色阈值=0.1]") print("示例: python awb_diff.py config_v1.xml config_v2.xml") print(" python awb_diff.py config_v1.xml config_v2.xml 0.03 0.08") sys.exit(1) # 解析阈值参数 yellow_threshold = 0.05 # 默认黄色阈值 red_threshold = 0.1 # 默认红色阈值 if len(sys.argv) >= 4: try: yellow_threshold = float(sys.argv[3]) if yellow_threshold <= 0: print("错误: 黄色阈值必须大于0") sys.exit(1) except ValueError: print("错误: 黄色阈值必须是数值类型") sys.exit(1) if len(sys.argv) >= 5: try: red_threshold = float(sys.argv[4]) if red_threshold <= 0 or red_threshold <= yellow_threshold: print("错误: 红色阈值必须大于0且大于黄色阈值") sys.exit(1) except ValueError: print("错误: 红色阈值必须是数值类型") sys.exit(1) file1 = sys.argv[1] file2 = sys.argv[2] results, global_warnings, global_row_checks = compare_ccmatrix_across_files( file1, file2, yellow_threshold, red_threshold ) # 打印报告头 print_colored_header(f" Awb_TblCCMatrix 参数对比报告 ", 80, Color.BLUE) print(f" 文件1: {colorize(file1, Color.CYAN)}") print(f" 文件2: {colorize(file2, Color.CYAN)}") print(f" 黄色阈值: {colorize(f'{yellow_threshold:.6f}', Color.YELLOW)}") print(f" 红色阈值: {colorize(f'{red_threshold:.6f}', Color.RED)}") print(colorize("-" * 80, Color.CYAN)) # 输出全局警告 if global_warnings: print_colored_header(" 警告: 检测到超过阈值的参数变更 ", 80, Color.RED) for warning in global_warnings: print(warning) print(colorize("!" * 80, Color.RED)) if results is None: print(colorize("\n无法生成报告: " + global_warnings[0], Color.RED)) return # 生成HTML报告 html_report = generate_html_report( results, global_warnings, global_row_checks, file1, file2, yellow_threshold, red_threshold ) # 保存并打开HTML报告 report_filename = "awb_diff_report.html" if save_and_open_html_report(html_report, report_filename): print(colorize(f"✅ HTML报告已生成并在浏览器中打开: {report_filename}", Color.GREEN)) else: print(colorize("❌ 无法生成HTML报告", Color.RED)) # 输出每个场景的详情到控制台 for result in results: scene = result["scene"] exists1 = result["exists_in_file1"] exists2 = result["exists_in_file2"] changes = result["changes"] row_checks = result["row_checks"] # 打印场景头 scene_header = f" 场景: {scene} " print_colored_header(scene_header, 80, Color.BLUE) print(f" 文件1中存在: {colorize('是', Color.GREEN) if exists1 else colorize('否', Color.RED)}") print(f" 文件2中存在: {colorize('是', Color.GREEN) if exists2 else colorize('否', Color.RED)}") if exists1 and exists2: if changes: print(f" 检测到 {len(changes)} 处变化:") # 按变化类型分组 num_changes = [c for c in changes if c["type"] in ["数值", "汇总"]] non_num_changes = [c for c in changes if c["type"] == "非数值"] struct_changes = [c for c in changes if c["type"] == "结构"] if num_changes: print(colorize("\n [数值变化]:", Color.BOLD)) for change in num_changes: # 确定颜色 if change["warning_level"] == "red": color = Color.RED elif change["warning_level"] == "yellow": color = Color.YELLOW else: color = Color.GREEN # 格式化输出 path_display = colorize(change["path"], color) # 为ctemp相关的变化添加特殊标记 ctemp_note = colorize(" (ctemp变化)", Color.CYAN) if "ctemp" in change["path"].lower() else "" # 格式化输出差值 if "数值" in change["type"]: sign = "+" if change["delta"] >= 0 else "-" diff_str = colorize(f" | 变化: {sign}{abs(change['diff']):.6f}", color) else: diff_str = "" print(f" {path_display}: {change['change']}{diff_str}{ctemp_note}") if non_num_changes: print(colorize("\n [非数值变化]:", Color.BOLD)) for change in non_num_changes: print(f" {change['path']}: {change['change']}") if struct_changes: print(colorize("\n [结构变化]:", Color.BOLD)) for change in struct_changes: print(f" {change['path']}: {change['change']}") else: print(colorize("\n ✅ 无变化", Color.GREEN)) # 输出该场景的矩阵行和检查 if row_checks: # 检查是否所有行都通过 all_passed = all(check["valid"] for check in row_checks) if all_passed: print(colorize("\n [矩阵行和检查]:", Color.BOLD)) print(colorize(f" ✅ 所有行和检查通过 (每行和≈1.000000)", Color.GREEN)) else: print(colorize("\n [矩阵行和检查]:", Color.BOLD)) print(colorize(f" ❌ 以下行和检查失败:", Color.RED)) for check in row_checks: if not check["valid"]: print(colorize(f" {check['path']}: 和={check['sum']:.6f} ≠ 1.000000", Color.RED)) print(colorize(f" 值: {' '.join(f'{v:.6f}' for v in check['values'])}", Color.YELLOW)) if __name__ == "__main__": try: main() except KeyboardInterrupt: print(colorize("\n程序被用户中断", Color.RED)) sys.exit(1) ``` ### 代码解释 这段代码实现了以下核心功能: 1. **XML解析与比较**: - 使用`xml.etree.ElementTree`解析XML文件 - 查找所有`Awb_TblCCMatrix`开头的节点 - 比较节点属性、文本内容和子节点结构 2. **数值分析**: - 检查矩阵每行求和是否为1(允许一定误差) - 数值变化分析(黄色/红色阈值警告) - 特殊处理ctemp相关的变化 3. **HTML报告生成**: - 生成美观的HTML报告,包含颜色编码 - 使用CSS实现响应式设计 - 不同警告级别使用不同颜色(红/黄/绿) 4. **报告保存与打开**: - 在同目录下保存为`awb_diff_report.html` - Windows系统使用`os.startfile()`自动打开 - 其他系统使用`webbrowser.open()` 5. **控制台输出**: - 使用colorama实现彩色控制台输出 - 详细显示每个场景的变化情况 - 矩阵行和检查结果可视化 ### 使用说明 1. **运行脚本**: ```bash python awb_diff.py 文件1.xml 文件2.xml [黄色阈值] [红色阈值] ``` 示例: ```bash python awb_diff.py config_v1.xml config_v2.xml 0.03 0.08 ``` 2. **输出结果**: - 控制台显示彩色对比结果 - 同目录下生成`awb_diff_report.html` - 自动在默认浏览器中打开HTML报告 3. **报告特点**: - 顶部标题区域显示文件信息和阈值 - 全局警告使用醒目的颜色块显示 - 每个场景单独展示,包含变化详情 - 矩阵行和检查结果用颜色标识 - 响应式设计适应不同屏幕尺寸 ### 技术亮点 1. **路径处理**: ```python script_dir = os.path.dirname(os.path.abspath(__file__)) report_path = os.path.join(script_dir, filename) ``` 确保报告始终保存在脚本同目录下 2. **Windows打开方式**: ```python if platform.system() == 'Windows': os.startfile(report_path) ``` 使用系统原生方式打开文件,避免路径问题 3. **HTML样式设计**: ```css .warning-red { background-color: #ffebee; border-left: 5px solid #f44336; } ``` 使用现代CSS设计,包括渐变、阴影和悬停效果 4. **矩阵行和检查**: ```python def check_row_sum(values, tolerance=1e-3): # 检查每行求和是否为1 ``` 确保矩阵数据的数学正确性
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肆十二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值