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))" />
我的 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))" />