XSD 任意但固定数量的元素
XSD arbitrary but fix number of elements
我有以下 XSD 文件:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="list">
<xsd:complexType>
<xsd:sequence><!--arbitrary number of log entries-->
<xsd:element name="vocable" minOccurs="0" maxOccurs="unbounded"><!--a log entry is a complex type-->
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstLanguageTranslations" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="firstLanguagePhoneticScripts" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="secondLanguageTranslations" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="secondLanguagePhoneticScripts" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="topics" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="chapters" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="description" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="learnLevel" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="relevanceLevel" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
现在我想改一下,让最里面的sequence里面有<key>attribute name</key>
和<value>value</value>
的元素对,这样在我的程序中,我可以简单地添加新的属性。但是,我希望每个可调用元素的这些属性都相同。我如何确保在 XSD 文件中?
我将列出 XSD 文件的要求以使其更清楚:
- XML 文件可以包含任意数量的词汇
- 一个词汇可以包含任意数量的属性
- 一个vocable的属性对所有vocables都是一样的(相同的数量,相同的键)
- 属性使用
<key>attribute name</key>
和 <value>attribute value</value>
表示
如果使用键和值元素不是执行此操作的最佳方法,我愿意接受其他建议。
编辑#1:
为了更清楚,我将添加两个示例:
应有效:
<?xml version="1.0" encoding="utf-8" ?>
<list>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
</vocable>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
</vocable>
</list>
同样有效,因为词汇具有相同的属性:
<?xml version="1.0" encoding="utf-8" ?>
<list>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
<key>something</key>
<value>word4</value>
</vocable>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
<key>something</key>
<value>word3</value>
</vocable>
</list>
无效,因为词汇不具有相同的属性:
<?xml version="1.0" encoding="utf-8" ?>
<list>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
</vocable>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
<key>something else</key>
<value>word3</value>
</vocable>
</list>
编辑#2:
为什么这对我很重要:
我希望用户能够在他们认为合适的情况下向我的程序中的 vocable 添加(或删除)属性,因为不同的人对 vocable 中应保存的内容有不同的期望和意见。我想在每次用户添加属性时不必编写代码来手动更改 XSD 文件。
同时,我希望能够让用户选择,一个vocable的哪些属性将显示在table个vocables中。当我知道每个 vocable 都有一个特定的属性时,这就容易多了。
架构设计
关于您的 XML 设计,除了 key
和 value
元素外,一切看起来都很好。想象一下,例如,有人想从这样的文档中 select secondLanguageTranslation
的值。在 XPath 中,他们必须按照
的方式做一些事情
/list/vocable/key[. = 'secondLanguageTranslation']/following-sibling::value[1]
这是一个很长的声明!现在,让我们假设文档如下:
<list>
<vocable>
<firstLanguageTranslation>word1</firstLanguageTranslation>
<secondLanguageTranslation>word2</secondLanguageTranslation>
</vocable>
</list>
给定这个新文档,可以使用更简单的 XPath 表达式检索相同的信息:
/list/vocable/secondLanguageTranslation
哪个更容易阅读,即使元素名称有点长(主观性很强)。为了使我的观点更笼统:在 XML 中,元素不仅 包含 信息,它们 是 信息,在某种意义上元素的名称本身就是信息。 crystal-清晰,在
这样的结构中
<key>secondLanguage</key>
key
元素只不过是名称的容器,而在
<secondLanguage>word1</secondLanguage>
元素名称具有明确的语义,这与包含任何名称的 key
元素不同。或者,键和值很容易表示为属性:
<vocable secondLanguageTranslation="word1"/>
尤其是当键和值的内容永远都是单个单词时。
确保所有元素具有相同的任意元素集
话虽如此,我想我明白您为什么要引入 key
和 value
- 因为那样的话,对文档的更改将不需要您更改架构文档。而且,这也意味着您无法控制文档内容 - 您所知道的是有效文档包含 key
和 value
元素。控制文档的结构和内容正是 XML Schema 的用途。如果您的文档在不断发展,也许 XML 架构没有多大用处。
不过,认真对待 key
和 value
结构,确保元素的所有实例都具有相同的内容可以使用 assertions 来完成。确保所有 vocable
元素具有相同数量的 key
元素的断言可能如下:
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then count($x/key) = count($x/following-sibling::vocable[1]/key) else true())"/>
和比较所有 vocable
元素的键的规则:
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then (every $y in $x/key satisfies $y = $x/following-sibling::vocable[1]/key) else true())"/>
嵌入到一个完整的架构中:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="list">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="vocable" minOccurs="0" maxOccurs="unbounded" type="vocableType"/>
</xsd:sequence>
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then count($x/key) = count($x/following-sibling::vocable[1]/key) else true())"/>
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then (every $y in $x/key satisfies $y = $x/following-sibling::vocable[1]/key) else true())"/>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="vocableType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="key" type="xsd:string"/>
<xsd:element name="value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
断言必须发生在 list
的定义中,因为单个 vocable
元素内的断言只能访问以自身为根的子树。断言只能在XSD 1.1中使用,而这种规则在XSD 1.0中是完全不可能的。
如您所见,这种表达方式难以阅读 - 您能否阐明 为什么 您真的需要确保所有 vocable
元素具有相同的内容?特别是因为您似乎很满足于不知道文档中会出现哪些键。
我有以下 XSD 文件:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="list">
<xsd:complexType>
<xsd:sequence><!--arbitrary number of log entries-->
<xsd:element name="vocable" minOccurs="0" maxOccurs="unbounded"><!--a log entry is a complex type-->
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstLanguageTranslations" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="firstLanguagePhoneticScripts" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="secondLanguageTranslations" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="secondLanguagePhoneticScripts" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="topics" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="chapters" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="description" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="learnLevel" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="relevanceLevel" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
现在我想改一下,让最里面的sequence里面有<key>attribute name</key>
和<value>value</value>
的元素对,这样在我的程序中,我可以简单地添加新的属性。但是,我希望每个可调用元素的这些属性都相同。我如何确保在 XSD 文件中?
我将列出 XSD 文件的要求以使其更清楚:
- XML 文件可以包含任意数量的词汇
- 一个词汇可以包含任意数量的属性
- 一个vocable的属性对所有vocables都是一样的(相同的数量,相同的键)
- 属性使用
<key>attribute name</key>
和<value>attribute value</value>
表示
如果使用键和值元素不是执行此操作的最佳方法,我愿意接受其他建议。
编辑#1: 为了更清楚,我将添加两个示例: 应有效:
<?xml version="1.0" encoding="utf-8" ?>
<list>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
</vocable>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
</vocable>
</list>
同样有效,因为词汇具有相同的属性:
<?xml version="1.0" encoding="utf-8" ?>
<list>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
<key>something</key>
<value>word4</value>
</vocable>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
<key>something</key>
<value>word3</value>
</vocable>
</list>
无效,因为词汇不具有相同的属性:
<?xml version="1.0" encoding="utf-8" ?>
<list>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
</vocable>
<vocable>
<key>firstLanguageTranslation</key>
<value>word1</value>
<key>secondLanguageTranslation</key>
<value>word2</value>
<key>something else</key>
<value>word3</value>
</vocable>
</list>
编辑#2:
为什么这对我很重要:
我希望用户能够在他们认为合适的情况下向我的程序中的 vocable 添加(或删除)属性,因为不同的人对 vocable 中应保存的内容有不同的期望和意见。我想在每次用户添加属性时不必编写代码来手动更改 XSD 文件。 同时,我希望能够让用户选择,一个vocable的哪些属性将显示在table个vocables中。当我知道每个 vocable 都有一个特定的属性时,这就容易多了。
架构设计
关于您的 XML 设计,除了 key
和 value
元素外,一切看起来都很好。想象一下,例如,有人想从这样的文档中 select secondLanguageTranslation
的值。在 XPath 中,他们必须按照
/list/vocable/key[. = 'secondLanguageTranslation']/following-sibling::value[1]
这是一个很长的声明!现在,让我们假设文档如下:
<list>
<vocable>
<firstLanguageTranslation>word1</firstLanguageTranslation>
<secondLanguageTranslation>word2</secondLanguageTranslation>
</vocable>
</list>
给定这个新文档,可以使用更简单的 XPath 表达式检索相同的信息:
/list/vocable/secondLanguageTranslation
哪个更容易阅读,即使元素名称有点长(主观性很强)。为了使我的观点更笼统:在 XML 中,元素不仅 包含 信息,它们 是 信息,在某种意义上元素的名称本身就是信息。 crystal-清晰,在
这样的结构中<key>secondLanguage</key>
key
元素只不过是名称的容器,而在
<secondLanguage>word1</secondLanguage>
元素名称具有明确的语义,这与包含任何名称的 key
元素不同。或者,键和值很容易表示为属性:
<vocable secondLanguageTranslation="word1"/>
尤其是当键和值的内容永远都是单个单词时。
确保所有元素具有相同的任意元素集
话虽如此,我想我明白您为什么要引入 key
和 value
- 因为那样的话,对文档的更改将不需要您更改架构文档。而且,这也意味着您无法控制文档内容 - 您所知道的是有效文档包含 key
和 value
元素。控制文档的结构和内容正是 XML Schema 的用途。如果您的文档在不断发展,也许 XML 架构没有多大用处。
不过,认真对待 key
和 value
结构,确保元素的所有实例都具有相同的内容可以使用 assertions 来完成。确保所有 vocable
元素具有相同数量的 key
元素的断言可能如下:
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then count($x/key) = count($x/following-sibling::vocable[1]/key) else true())"/>
和比较所有 vocable
元素的键的规则:
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then (every $y in $x/key satisfies $y = $x/following-sibling::vocable[1]/key) else true())"/>
嵌入到一个完整的架构中:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="list">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="vocable" minOccurs="0" maxOccurs="unbounded" type="vocableType"/>
</xsd:sequence>
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then count($x/key) = count($x/following-sibling::vocable[1]/key) else true())"/>
<xsd:assert test="every $x in vocable satisfies (if ($x/following-sibling::vocable) then (every $y in $x/key satisfies $y = $x/following-sibling::vocable[1]/key) else true())"/>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="vocableType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="key" type="xsd:string"/>
<xsd:element name="value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
断言必须发生在 list
的定义中,因为单个 vocable
元素内的断言只能访问以自身为根的子树。断言只能在XSD 1.1中使用,而这种规则在XSD 1.0中是完全不可能的。
如您所见,这种表达方式难以阅读 - 您能否阐明 为什么 您真的需要确保所有 vocable
元素具有相同的内容?特别是因为您似乎很满足于不知道文档中会出现哪些键。