如何在两个不同的XML Schema之间进行映射?

XML Schema映射需显式定义,XSD自身不支持跨schema映射;常用方案是XSLT 2.0+处理实例转换,命名空间、日期格式、枚举值等须在XSLT中硬编码或查表,注释和appinfo不可靠,自动生成易出错。

XML Schema 映射不是自动发生的,必须显式定义规则

XML Schema(XSD)本身不提供跨 schema 的映射能力。xsd:importxsd:include 只解决命名空间合并和类型复用,不等同于字段级语义映射。如果你有两个独立的 XSD(比如 order-v1.xsdorder-edi850.xsd),它们的元素名、结构、数据类型甚至业务含义都可能不同,此时必须靠外部机制建立对应关系。

常用映射方式:XSLT 是最直接、可验证的方案

XSLT 2.0+ 支持强类型转换和模式匹配,适合处理 XSD 驱动的 XML 实例之间的转换。关键点在于:映射逻辑作用于 XML 实例(即符合某 XSD 的文档),而非 XSD 文件本身;XSD 仅用于校验输入/输出是否合法。

  • 先用 xmllint --schema order-v1.xsd input.xml 确保源 XML 合法
  • 编写 XSLT 时,用 匹配源结构,用 输出目标结构
  • 注意命名空间声明必须与目标 XSD 一致,例如 xmlns:edi="http://example.com/edi850"
  • 日期格式、枚举值映射(如 v1:Status = "shipped"edi:Status = "S")需在 XSLT 中硬编码或查表

  
    
      
      
    
  

避免把 XSD 注释或 appinfo 当作映射依据

有人尝试在 XSD 中用 添加类似 targetPath="/edi:Order/edi:ID" 的元信息,但这只是注释,没有任何工具会自动读取并执行它。主流验证器(xerces, libxml2)、编辑器(Oxygen)、甚至 JAXB 都忽略这类标记。

  • JAXB 的 @XmlRootElement(name="Order") 只控制 Java→XML 序列化,不解决跨 XSD 映射
  • OpenAPI-to-XSD 工具生成的 schema 缺乏语义关联,不能反向推导映射规则
  • 如果两个 XSD 共享相同 targetNamespace,但实际用途不同(如测试 vs 生产),仍需独立 XSLT

复杂映射场景下,手写 XSLT 比试图“自动生成”更可靠

所谓“XSD to XSD mapping 工具”(如 Altova MapForce 的 schema mode)最终仍导出 XSLT 或类似脚本。但自动生成常在以下地方出错:

  • 嵌套重复结构(如 v1:Itemedi:Loop230)无法正确识别层级边界
  • 条件逻辑缺失(如仅当 v1:Priority = "high" 才生成 edi:ExpediteFlag
  • 数据类型隐式转换失败(XSD 中 xs:decimal 对应的字符串含空格,XSLT 中未用 normalize-space() 清洗)

真正省时间的做法是:用 xmlstar 快速验证 XPath 表达式,再把调试好的路径填进 XSLT;对每个关键字段做 round-trip 测试——从 v1 XML → XSLT → EDI XML → 用 edi850.xsd 验证。