You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在XSD 1.0中定义具有两种形态的box元素?

XSD 1.0 实现box元素双形态验证的解决方案

问题概述

需要编写XSD 1.0验证XML文档,其中<box>元素存在两种互斥形态:

  • 形态1:无内容,必填属性name、weight,可选属性height
  • 形态2:包含若干子元素(可嵌套<box>),仅必填属性name,无其他属性

示例XML

<box name="box_1"> <!-- type 2 -->
    <box name="box_2"> <!-- type 2 -->
        <box name="box_3" weight="10" height="5" /> <!-- type 1 -->
        <box name="box_4" weight="15" /> <!-- type 1 -->
    </box>
    <box name="box_5"> <!-- type 2 -->
        <box name="box_6" weight="21" /> <!-- type 1 -->
    </box>
</box>
<box name="box_7" weight="21" /> <!-- type 1 -->

遇到的问题

  • XSD 1.0不支持<xs:alternative>,无法直接为同一元素定义条件类型
  • 无法在<xs:choice>中直接添加属性约束
  • 重复定义同名<box>元素会导致验证器优先匹配第一个类型,引发错误
  • weight属性在形态1中必须为必填,不能设为可选
  • 无法修改目标XML文档

无效的尝试方案

以下Schema因重复定义同名元素导致验证失败:

<xs:complexType name="closet">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="box" type="TboxComplex" />
        <xs:element name="box" type="TboxSimple" />
    </xs:choice>
</xs:complexType>

<xs:complexType name="TboxComplex">
    <xs:choice maxOccurs="unbounded">
            <xs:element name="box" type="TboxComplex" />
            <xs:element name="box" type="TboxSimple" />
    </xs:choice>
    <xs:attribute name="name"   type="xs:string"  use="required" />
</xs:complexType>

<xs:complexType name="TboxSimple">
    <xs:attribute name="name"   type="xs:string"  use="required" />
    <xs:attribute name="weight" type="xs:integer" use="required" />
    <xs:attribute name="height" type="xs:integer" use="optional" />
</xs:complexType>

验证报错信息

> xmllint --schema room.xsd room.xml 
room.xml:9: element box: Schemas validity error : Element 'box', attribute 'weight': The attribute 'weight' is not allowed.
room.xml:9: element box: Schemas validity error : Element 'box', attribute 'height': The attribute 'height' is not allowed.
room.xml:9: element box: Schemas validity error : Element 'box': Missing child element(s). Expected is ( box ).

解决方案

由于XSD 1.0本身不支持基于内容的条件属性约束,我们需要结合XSD基础验证+Schematron规则来实现完整约束,无需修改XML或切换至XSD 1.1。

步骤1:编写基础XSD Schema

该Schema定义<box>元素的所有可能结构,放宽属性的必填性,后续用Schematron补充条件约束:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="root"> <!-- 可根据实际文档调整根元素名称 -->
        <xs:complexType>
            <xs:choice maxOccurs="unbounded">
                <xs:element ref="box"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>

    <xs:element name="box">
        <xs:complexType>
            <xs:choice maxOccurs="unbounded" minOccurs="0">
                <xs:element ref="box"/>
            </xs:choice>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="weight" type="xs:integer"/>
            <xs:attribute name="height" type="xs:integer"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

步骤2:编写Schematron规则

添加条件约束,实现两种形态的互斥验证:

<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron">
    <sch:pattern name="Box形态约束">
        <!-- 约束1:无子元素的box必须包含weight属性 -->
        <sch:rule context="box[not(*)]">
            <sch:assert test="@weight">无子元素的box必须包含必填属性weight</sch:assert>
        </sch:rule>

        <!-- 约束2:有子元素的box不能包含weight或height属性 -->
        <sch:rule context="box[*]">
            <sch:assert test="not(@weight)">有子元素的box不能包含weight属性</sch:assert>
            <sch:assert test="not(@height)">有子元素的box不能包含height属性</sch:assert>
        </sch:rule>
    </sch:pattern>
</sch:schema>

验证方式

使用支持Schematron的工具(如带Schematron插件的xmllint、Oxygen XML Editor等)进行验证:先通过XSD验证结构合法性,再通过Schematron验证业务规则。

如果必须仅使用XSD 1.0而不借助Schematron,无法完全实现weight的条件必填约束,只能接受放宽属性要求,但可通过注释明确业务规则。


内容的提问来源于stack exchange,提问作者T.P.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:42:04