在异构系统之间搬运表格数据时,XML凭借自描述性和严格的嵌套结构成为常见载体。所谓用XML表示表格数据,本质是把二维关系中的行、列以及字段语义翻译成元素与属性的组合,使任意支持XML解析的语言都能还原出原来的表。与纯文本表格不同,XML节点本身就可以携带列名、数据类型甚至校验规则,这在跨团队对接时尤其重要。

基础行集模型:用重复节点表达二维表
最直观的思路是把每一行写成一个 <row> 元素,行内每个单元格作为子元素,元素名对应列名。这种方式对人类阅读友好,字段含义直接写在标签上,不需要额外说明哪一列是什么。例如一张用户表包含编号、姓名、年龄,就可以用下面这样的结构表达。
不过这种写法在列数很多或者字段可能为空时会产生大量冗余标签,而且如果某些行缺少某个字段,解析程序必须做存在性判断。另外,当列名本身包含空格或特殊字符时,直接作为标签名并不合法,需要使用属性或下划线转义。下面的示例展示了一个简单但完整的行集模型,其中每行数据都通过子元素显式列出字段。
<users>
<row>
<id>1</id>
<name>张三</name>
<age>28</age>
</row>
<row>
<id>2</id>
<name>李四</name>
<age>34</age>
</row>
</users>
从解析角度看,使用 DOM 或 SAX 读取上述结构时,只要遍历 <users> 下的 <row> 节点,再取各自子节点文本即可还原表格。它的优点是改动列名时数据结构依旧清晰,缺点是数据量增大时文件体积远超 CSV,因为每一个值都被一对标签包裹。
表头与数据分离:提升校验与映射效率
当表格列定义稳定但数据行极多时,更好的模式是把列信息集中在表头,数据行只按位置或简短属性存值。这样既能用一份元数据描述所有行的含义,也方便用 XML Schema 限制类型。比如用 <columns> 声明三列,然后 <data> 中每行用 <value> 列表或者属性表达,解析器先读表头建立索引,再按索引取数。
这种分离结构特别适合数据库导出场景。假设从关系型库查出一千行记录,若每行都重复列名标签会非常臃肿;而先输出列定义,数据部分仅保留值,体积可缩小一半以上。同时,由于列名只在头部出现,重命名列只改一处,下游映射代码通过列标识而非标签名关联,更不容易出错。下面给出一个带表头声明的例子。
<table>
<columns>
<column name="id" type="integer"/>
<column name="name" type="string"/>
<column name="age" type="integer"/>
</columns>
<data>
<row>
<value>1</value>
<value>张三</value>
<value>28</value>
</row>
<row>
<value>2</value>
<value>李四</value>
<value>34</value>
</row>
</data>
</table>
在程序映射时,可先使用 getElementsByTagName 获取 column 节点,将其 name 与 type 存入数组,再遍历 data 中的 row,按顺序把 value 文本转换成对应类型。这样做既保留了 XML 的自描述优势,又避免了标签膨胀,还能直接对接 ORM 框架的字段配置。
属性与元素的选择及实际对接建议
除了用子元素,也可以把单元格值写成元素属性,例如 <row id="1" name="张三" age="28"/>。属性写法更紧凑,但 XML 规范中属性难以表达多行文本且顺序不严格,不适合复杂内容;元素写法虽然冗长,却允许嵌套、注释与混合内容。因此在表示表格时,若字段都是简单标量,属性方案能明显减少字符数,若字段可能包含结构化子表则必须用元素。
实际项目中,我们常把数据库查询结果序列化为 XML 交给外部系统。此时建议固定一套命名规则:表名对应根节点,列定义放头部,数据行用统一标签。遇到空值可用 xsi:nil="true" 标记而非省略节点,防止解析端错位。如下代码片段演示了在 Python 中利用标准库生成带表头的 XML 表格,可供参考。
import xml.etree.ElementTree as ET
def build_table_xml(rows):
root = ET.Element("table")
cols = ET.SubElement(root, "columns")
for c in ["id", "name", "age"]:
ET.SubElement(cols, "column", name=c, type="string")
data = ET.SubElement(root, "data")
for r in rows:
row = ET.SubElement(data, "row")
for v in r:
val = ET.SubElement(row, "value")
val.text = str(v)
return ET.tostring(root, encoding="utf-8")
print(build_table_xml([(1, "张三", 28), (2, "李四", 34)]))
总体来看,XML 表示表格数据没有唯一标准,关键在于让结构匹配消费端解析能力。轻量接口可用属性行集,海量数据用表头分离,需要严格约束就配合 Schema。只要团队内部约定清晰,XML 完全能承担稳定的表格交换任务。