如何使XSD的DataArray_t支持任意简单类型,解决大数值存储问题?
问题描述
我们尝试用XML格式存储粒子数据,现有XSD代码基本可用,但向DataArray_t存储大unsigned long值时出现异常,原因是DataArrayList_t的基类型为xsd:decimal(无法精确表示超大无符号长整数)。由于DataArray_t需要支持存储任意类型数据(如int、unsigned long、double等),希望知道是否可通过参数形式任意修改DataArrayList_t的itemType?
现有XSD代码:
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:simpleType name='DataArrayList_t'> <xsd:list itemType='xsd:decimal'/> </xsd:simpleType> <xsd:complexType name="DataArray_t"> <xsd:simpleContent> <xsd:extension base="DataArrayList_t"> <!-- hier typ der daten in liste --> <xsd:attribute name="type" use="required"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Int8"/> <xsd:enumeration value="UInt8"/> <xsd:enumeration value="Int16"/> <xsd:enumeration value="UInt16"/> <xsd:enumeration value="Int32"/> <xsd:enumeration value="UInt32"/> <xsd:enumeration value="Int64"/> <xsd:enumeration value="UInt64"/> <xsd:enumeration value="Float32"/> <xsd:enumeration value="Float64"/> </xsd:restriction> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="Name" type="xsd:string" use="required"/> <xsd:attribute name="NumberOfComponents" type="xsd:integer" use="required"/> <xsd:attribute name="format" type="xsd:string" fixed="ascii"/> <xsd:attribute name="offset" type="xsd:integer" use="optional"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <xsd:complexType name="PieceUnstructuredGrid_t"> <xsd:sequence> <xsd:element name="PointData"> <xsd:complexType> <xsd:sequence> <xsd:element name="DataArray" type="DataArray_t" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="CellData"> <xsd:complexType> <xsd:sequence> <xsd:element name="DataArray" type="DataArray_t" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="Points"> <xsd:complexType> <xsd:sequence> <xsd:element name="DataArray" type="DataArray_t" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="Cells"> <xsd:complexType> <xsd:sequence> <xsd:element name="DataArray" type="DataArray_t" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="NumberOfPoints" type="xsd:integer" use="required"/> <xsd:attribute name="NumberOfCells" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:schema>
解决方案说明
XSD 1.0不支持通过参数动态修改list的itemType,因为类型定义是静态的,无法根据属性值动态调整。但可以通过以下几种方案解决类型兼容问题:
方案1:改用字符串列表存储(最灵活)
将DataArrayList_t的基类型改为xsd:string,所有数值以字符串形式存储,通过type属性约定实际类型,在解析阶段再做类型转换。这种方式完全避免了数值类型的精度限制,能支持所有枚举的类型。
修改后的DataArrayList_t定义:
<xsd:simpleType name='DataArrayList_t'> <xsd:list itemType='xsd:string'/> </xsd:simpleType>
方案2:为每种类型定义单独列表(XSD 1.0严格校验)
为每个枚举类型定义对应的list类型,然后在DataArray_t中使用<xsd:choice>选择对应类型的列表,同时在应用层保证type属性与实际列表类型一致。
示例修改片段:
<!-- 定义各类型对应的列表 --> <xsd:simpleType name='Int8List_t'> <xsd:list itemType='xsd:byte'/> </xsd:simpleType> <xsd:simpleType name='UInt8List_t'> <xsd:list itemType='xsd:unsignedByte'/> </xsd:simpleType> <xsd:simpleType name='UInt64List_t'> <xsd:list itemType='xsd:unsignedLong'/> </xsd:simpleType> <!-- 其他类型列表定义省略 --> <!-- 修改DataArray_t结构 --> <xsd:complexType name="DataArray_t"> <xsd:choice> <xsd:element name="Int8Data" type="Int8List_t"/> <xsd:element name="UInt8Data" type="UInt8List_t"/> <xsd:element name="UInt64Data" type="UInt64List_t"/> <!-- 其他类型对应的element添加 --> </xsd:choice> <xsd:attribute name="type" use="required"> <!-- 原有枚举定义不变 --> </xsd:attribute> <!-- 其他属性定义不变 --> </xsd:complexType>
该方案能在XSD层面实现严格类型校验,但定义较为冗长,新增类型时需同步扩展XSD。
方案3:使用XSD 1.1条件类型赋值(最优雅)
如果可以升级到XSD 1.1,可利用条件类型赋值特性,根据type属性的值动态绑定对应的列表类型,完美匹配需求。
示例实现片段:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <!-- 定义各类型对应的列表 --> <xsd:simpleType name='Int8List_t'> <xsd:list itemType='xsd:byte'/> </xsd:simpleType> <xsd:simpleType name='UInt8List_t'> <xsd:list itemType='xsd:unsignedByte'/> </xsd:simpleType> <xsd:simpleType name='UInt64List_t'> <xsd:list itemType='xsd:unsignedLong'/> </xsd:simpleType> <!-- 其他类型列表定义省略 --> <!-- 带条件类型赋值的DataArray_t --> <xsd:complexType name="DataArray_t"> <xsd:simpleContent> <xsd:extension base="xsd:anySimpleType"> <xsd:attribute name="type" use="required"> <!-- 原有枚举定义不变 --> </xsd:attribute> <!-- 其他属性定义不变 --> </xsd:extension> </xsd:simpleContent> <!-- 根据type属性选择对应列表类型 --> <xsd:alternative test="@type='Int8'" type="Int8List_t"/> <xsd:alternative test="@type='UInt8'" type="UInt8List_t"/> <xsd:alternative test="@type='UInt64'" type="UInt64List_t"/> <!-- 其他类型的alternative添加 --> <xsd:alternative type="xsd:string"/> <!-- 默认 fallback --> </xsd:complexType> <!-- 原有PieceUnstructuredGrid_t等定义不变 --> </xsd:schema>
该方案既保留了type属性的语义,又能在XSD层面完成类型校验,但需要支持XSD 1.1的解析器(如Xerces2、Saxon)。
内容的提问来源于stack exchange,提问作者Felix Hoppe

