XSD 文件确保出现无限次的元素的属性不是恰好设置一次?

XSD file ensure that an attribute of an element that occurs an unbounded number of times is NOT set exactly one time?

我的 xml 文件有一个带有可选属性 lang 的元素。

例如

<movie>
    <title>Lord of the Rings</title>
    <title lang="ger">Herr der Ringe</title>
    <title lang="esp">El Senor de los Anillos</title>
</movie>
<movie>
    <title>Game of Thrones</title>
</movie>
<movie>
    <title>Star War</title>
    <title lang="fra">Guerre des etoiles</title>
    <title lang="ger">Krieg der Sterne</title>
</movie>

有什么方法可以确保在 xml 模式中每部电影都有一个没有任何属性的电影 "lang" 如果还有更多的电影,他们需要有这个属性。

这不完全是您所要求的,但它可能是您想要的:我认为您可以通过为属性定义一个默认值(例如 "en")然后检查所有价值观是独一无二的。您可以在 xs:attribute 声明中定义默认值,并且可以在 movie 元素的声明中使用

定义唯一性
<xs:unique name="unique-lang">
  <xs:selector xpath="title"/>
  <xs:field xpath="@lang"/>
</xs:unique>

这不会阻止默认值明确出现在英文版的标题中,但我想您可以接受。

我建议使用国际标准语言代码,而不是自己编写。

我喜欢 Michael Kay 的方法,它很简单。

尽管同时我尝试了 xs:assert 的方法(警告:需要 XSD 1.1,但 at least Xerces, with PsychoPath and Saxon 支持)并且不想向您隐瞒。这个想法是简单地将属性保留为可选,但要断言第一项是否已设置。我不确定这是否可以表达得更简单,但这里是:

<xs:element name="movie" type="t:tpMovie" />

<xs:complexType name="tpMovie">
    <xs:sequence>            
        <xs:element name="title"  minOccurs="1" type="t:tpTitle" maxOccurs="unbounded">
        </xs:element>
    </xs:sequence>        
    <xs:assert test="t:title[1][not(@lang)]" />
    <xs:assert test="every $t in t:title[1]/following-sibling::t:title satisfies not(empty($t/@lang))" />
</xs:complexType>

<xs:complexType name="tpTitle">
    <xs:attribute name="lang" use="optional"/>
</xs:complexType>

使用以下输入:

<movie .. ns removed for brevity..>    
    <title />
    <title lang="en"/>
    <title lang="es" />
    <title  />
</movie>

或:

<movie ..ns removed for brevity..>    
    <title lang="de"/>
    <title lang="en"/>
    <title lang="es" />
</movie>

您将收到断言错误。

虽然以下操作成功:

<movie ..ns removed for brevity..>    
    <title />
    <title lang="de"/>
    <title lang="en"/>
    <title lang="es" />
</movie>

更新(新要求,参见 comment

如果你想测试至少一个没有 @lang 的标题,其余的必须有 lang 属性,那么你可以这样写(删除另一个断言):

<xs:assert test="count(t:title[not(@lang)]) = 1" />

最后我找到了对我有用的东西: <xs:assert test="(count(title) = 0) or (count(title[@*]) + 1 = count(title))" />