XML
XML 是一种文本格式,可将自定义标签嵌套成结构化数据树。介绍其语法、架构、PASCAL VOC 标注,以及与 JSON 和 YAML 的比较。
XML(可扩展标记语言)是一种结构化数据文本格式,自定义标签可以相互嵌套形成树形结构,例如一个 <size> 元素包含 <width> 和 <height>。万维网联盟于 1998 年 2 月将 XML 1.0作为推荐标准发布;它是 SGML(标准通用标记语言)的简化子集,旨在用于网络上的文档和数据交换。与 HTML 不同,XML 没有预定义标签:每个应用都会为数据定义自己的标签,因此许多文件格式都以 XML 为基础,从 SVG 图形和 RSS 源到 Microsoft Office 文档都是如此。在机器学习和计算机视觉领域,XML 主要用于标注文件、模型文件,以及提供训练数据的医疗保健和企业系统。
XML 语法与验证#
XML 文档必须且只能有一个根元素。元素可以包含文本、子元素,以及写在起始标签中的属性,例如 <box label="car" xtl="10">;通过 xmlns 声明的命名空间可以区分不同词汇体系中的标签。符合语法规则的文档必须关闭所有标签、正确嵌套元素并为属性值加引号,这类文档称为格式良好的文档;解析器遇到第一个格式错误时必须停止。如果文档符合以文档类型定义(DTD)或 XML Schema(XSD)编写的架构,其中列出了允许的元素、元素顺序及其数据类型,那么该文档也是有效的。size/width 等 XPath 表达式用于从树中选择节点,而 XSLT 样式表可以将一种 XML 词汇体系转换为另一种。
XML 在计算机视觉和机器学习中的应用#
2005 年至 2012 年举办的 PASCAL VOC挑战赛让 XML 成为目标检测领域的经典标注格式。每张图像对应一个 XML 文件,其中包含文件名、图像尺寸,以及每个目标各自的 <object> 元素;元素中保存类别名称、truncated 和 difficult 标志,以及 <bndbox>,其像素角点 xmin、ymin、xmax 和 ymax 定义了边界框。LabelImg 标注工具默认会保存为这种格式,因此许多数据集仍采用该格式,并且需要在数据预处理时进行转换。CVAT导出的 CVAT for images 1.1 格式会在单个 XML 文件中保存某个任务的全部标注,框则写成属性,例如 xtl、ytl、xbr 和 ybr。
XML 还用于描述模型和记录。Intel 的 OpenVINO 中间表示会将网络的层和连接存储在 .xml 文件中,并将权重存储在配套的 .bin 文件中;OpenCV 预训练的 Haar 级联人脸检测器也以 XML 格式分发。HL7 FHIR 健康记录可通过 XML 或 JSON 交换,临床 AI 项目会将这些记录与图像配对,用于医学图像分析;Word 和 Excel 文件则是 ZIP 压缩包,其中包含供 AI 系统读取的 XML 部件。
此示例使用 Python 内置的 ElementTree解析 VOC 标注,并将每个框转换为YOLO 标注格式中归一化的中心坐标、宽度和高度:
import xml.etree.ElementTree as ET
# A PASCAL VOC annotation: one XML file per image, one <object> per box
voc = """
<annotation>
<filename>000017.jpg</filename>
<size><width>480</width><height>364</height><depth>3</depth></size>
<object><name>person</name><difficult>0</difficult>
<bndbox><xmin>185</xmin><ymin>62</ymin><xmax>279</xmax><ymax>199</ymax></bndbox></object>
<object><name>horse</name><difficult>0</difficult>
<bndbox><xmin>90</xmin><ymin>78</ymin><xmax>403</xmax><ymax>336</ymax></bndbox></object>
</annotation>
"""
root = ET.fromstring(voc)
w, h = int(root.find("size/width").text), int(root.find("size/height").text)
# Convert corner pixels to YOLO's normalized center x, center y, width, height
for obj in root.iter("object"):
box = obj.find("bndbox")
x1, y1, x2, y2 = (float(box.find(k).text) for k in ("xmin", "ymin", "xmax", "ymax"))
cx, cy = ((x1 + x2) / 2 - 1) / w, ((y1 + y2) / 2 - 1) / h # VOC pixel indices start at 1
print(obj.find("name").text, f"{cx:.3f} {cy:.3f} {(x2 - x1) / w:.3f} {(y2 - y1) / h:.3f}")它会打印 person 0.481 0.356 0.196 0.376 和 horse 0.511 0.566 0.652 0.709:这两个框以图像尺寸的比例表示,可在类别索引之后写入标注行。Ultralytics VOC.yaml 数据集文件会在首次使用时自动执行转换,下载 VOC 2007 和 2012,使用 ElementTree 解析每个 XML 标注,跳过标记为 difficult 的目标,并为 16,551 张训练图像和 4,952 张验证图像写入 YOLO .txt 标注。
XML、JSON 与 YAML#
- JSON:由对象、数组、字符串、数字和布尔值组成,语法比 XML 更简洁,并且可直接映射到 Python 字典和 JavaScript 对象。Web API 和COCO 数据集标注都使用 JSON。
- YAML: 使用缩进代替闭合标签,支持注释;自 YAML 1.2 起还可以接受任何 JSON 文档,因此常用于手工编辑配置,例如 YOLO 数据集和模型文件。
- XML: 语法更加冗长,支持架构、命名空间、属性和混合内容(即包含内联标记的文本),适用于需要严格验证的文档和标准组织。
解析不可信的 XML#
XML 的实体功能允许文档定义可复用文本,攻击者会滥用这一功能。在“十亿笑声”攻击中,大约十个嵌套实体定义会各自引用前一个定义十次,最终将一个只有几百字节的文件扩展成数 GB 文本。XML 外部实体(XXE)攻击会声明一个指向本地文件或内部 URL 的实体,导致有漏洞的解析器将机密读入文档,或从内部网络发送请求。Python 的 xml.etree.ElementTree 不会展开外部实体,并且遇到外部实体时会引发解析错误;从 Expat 2.4.1 起,其解析器也能抵御“十亿笑声”攻击。defusedxml包采取了更严格的措施:遇到任何实体声明(无论内部还是外部)都会引发 EntitiesForbidden。










