XSD任意但固定元素数量

时间:2015-08-21 15:48:40

标签: xml xsd

我有以下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>

现在我想改变它,所以在最内层的序列中,有<key>attribute name</key><value>value</value>的元素对,所以在我的程序中,我可以简单地添加新的属性。但是,我希望每个vocable元素的这些属性都相同。我如何确保在XSD文件中?

我将列出XSD文件的要求,使其更加清晰:

  1. XML文件可以包含任意数量的vocable
  2. vocable可以包含任意数量的属性
  3. vocable的属性对于所有vocable都是相同的(相同数量,相同的键)
  4. 使用<key>attribute name</key><value>attribute value</value>
  5. 表示属性

    如果使用键和值元素不是最好的方法,我愿意接受其他建议。

    修改#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>
    

    同样有效,因为vocable具有相同的属性:

    <?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>
    

    无效,因为vocables没有相同的属性:

    <?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添加(或删除)属性,因为不同的人对于应该在v​​ocable中保存的内容有不同的期望和意见。我希望这样做,而无需每次用户添加属性时编写代码来手动更改XSD文件。 同时,我希望能够让用户选择,vocable的哪些属性将显示在vocables表中。如果我知道,每个vocable都有一个特定的属性,这就容易多了。

1 个答案:

答案 0 :(得分:1)

架构设计

关于您的XML设计,除keyvalue元素外,一切看起来都很好。例如,想象一下,有人想要从这样的文档中选择 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中,元素不仅包含信息,而且信息,因为元素的名称本身信息。要清晰,在像

这样的结构中
<key>secondLanguage</key>

key元素只不过是名称的容器,而在

<secondLanguage>word1</secondLanguage>

元素名称具有明确的语义,与key元素不同,后者包含任何名称。或者,键和值很容易表示为属性:

<vocable secondLanguageTranslation="word1"/>

特别是如果键和值的内容只是单个单词。

确保所有元素都具有相同的任意元素集

那就是说,我想我理解你为什么要介绍keyvalue - 因为那时,对文档的更改不需要你更改架构文档。但是,这意味着您失去了对文档内容的控制 - 您只知道有效文档包含keyvalue元素。控制文档的结构和内容正是XML Schema的用途。如果您的文档不断发展,也许没有任何XML Schema可用。

仍然认真对待keyvalue结构,确保所有元素实例具有相同的内容可以使用断言完成。确保所有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元素具有相同的内容?特别是因为你似乎非常满足于不知道文档中会出现哪些密钥。