【问题标题】:Creating and using derived types in XML schema在 XML 模式中创建和使用派生类型
【发布时间】:2014-10-18 17:25:23
【问题描述】:

编辑是为了制作一个完整的架构,如果需要,可以按照下面的 cmets 中的建议进行测试

假设我有一个小的 XML 模式定义如下:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
           targetNamespace="tns:grades"
           elementFormDefault="qualified"
           xmlns:tns="tns:grades"
           vc:minVersion="1.1">

    <xs:element name="grades">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="tns:grade" minOccurs="0" maxOcccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="grade">
        <xs:complexType>
            <xs:simpleContent>
                <xs:extension base="xs:double">
                    <xs:attribute name="type" type="tns:gradeType" use="required"/>
                </xs:extension>
            </xs:simpleContent>
        </xs:complexType>
    </xs:element>

    <xs:simpleType name="gradeType">
        <xs:restriction base="xs:string">
            <xs:pattern value="simple|complex"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="simple">
        <xs:restriction base="xs:double">
            <xs:pattern value="1.0|1.3|1.7|2.0|2.3|2.7|3.0|3.3|3.7|4.0|4.7|5.0"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="complex">
        <xs:restriction base="xs:double">
            <xs:minInclusive value="1.0"/>
            <xs:maxInclusive value="5.0"/>
        </xs:restriction>
    </xs:simpleType>

</schema>

类型 gradeType 用于确定 grade 元素的值如何限制以及如何评估它。我想要做的是使用上面指定的 simple 和 complex 类型作为 gradeType 的两个派生。由于评分标准的限制,简单类型的评分只允许我使用一组有限的选项。另一方面,complex 类型基本上允许我在 1.0 和 5.0 之间有一个无限的区间,因为我使用它来计算多个 simple 等级的算术平均值并将其四舍五入到最接近的值simple 等级在 XSLT 中可用。但是我不知道如何更改我的 gradeType 以便在创建一个简单类型 simple 和 complex 时可以使用等级元素。我已经阅读了有关从基类(此处:gradeType)派生类型(此处:simple,complex)的信息,但似乎我根本没有不明白。

我想象的 grade 应该是什么样子的示例:

<grades>
    <grade type="simple">1.7</grade>
    <grade type="simple">2.0</grade>
    <grade type="complex">1.4</grade>
    <grade type="simple">5.0</grade>
    <grade type="complex">4.6</grade>
</grades>

编辑 如下所示,xs:union 元素已经过测试:

<xs:simpleType name="gradeType">
    <xs:union memberTypes="tns:simple tns:complex"/>
</xs:simpleType>

这导致我的 XML 文档中的所有 grade 元素出现以下两个错误:

cvc-datatype-valid.1.2.3:“simple”不是联合类型“gradeType”的有效值。

cvc-attribute.3:元素“grade”上的属性“type”的值“simple”相对于其类型“gradeType”无效。

编辑 2: 正如@lexicore 所指出的,我或多或少都错了,或者可能只是解释得很糟糕。我将尝试使用伪代码来描述 grade 元素应该如何工作:

if gradeType == "simple"
    value of GRADE has to obey the rules defined by the SIMPLE type
else if gradeType == "complex"
    value of GRADE has to obey the rules defined by the COMPLEX type

【问题讨论】:

    标签: xml xsd complextype derived-types simpletype


    【解决方案1】:

    经过长时间的挣扎,我想出了以下方法,它正在做我希望它做的事情,但有两个例外:

    • 即使用法设置为 required 的 type 属性实际上也可以省略,这明显违反了我的 grade 元素的方式应该可以工作
    • grade可能一下子就空了-_-

    这些问题很可能是因为我的 grade 属性实际上来自我的基本类型 gradeType。

    正如您在下面看到的,我已经对处理 grade 元素的部分重新编写了我的 XSD。我添加了一些我需要的附加属性(在我的问题中没有描述@term 和@attempt)。在后面的解释之后可以看到下面的XSD代码。

    我从一些蛮力技术开始,试验我可以用 xs:complexType 和 xs:simpleType 做出什么样的组合,因为我的想法实际上是围绕这两个.然后我开始研究以多种方式描述同一元素的替代方法。关键字 alternatives 给了我寻找这样一个元素的想法,确实 xs:alternative 是我的解决方案。主要的突破是当我记得一个元素可以有 4 种类型的内容:空(即根本没有内容)、文本、另一个元素或组合。主要问题是,我设法找到的所有关于 xs:alternative 的示例都包含它们所属的当前元素的子元素的嵌套结构的替代方案。我决定用 text 内容对其进行测试,它确实有效。所以它是这样工作的:你创建一个 complexType gradeType,它用于两件事 - 描述我的 grade 元素的属性并且是我想要的两种成绩的基础 - 简单和复杂。它也被定义为 simpleType xs:double 的扩展。这三个的共同点是它们是 complexType 并且当您想要使用 xs:restriction 并创建时需要第二个 simpleContent simpleType (xs:double) 的容器。

    <xs:element name="grade">
        <xs:alternative test='@type="simple"' type="tns:simple"/>
        <xs:alternative test='@type="complex"' type="tns:complex"/>
    </xs:element>
    
    <xs:complexType name="gradeType">
        <xs:simpleContent>
            <xs:extension base="xs:double">
                <xs:attribute name="attempt" use="required">
                    <xs:simpleType>
                        <xs:restriction base="xs:nonNegativeInteger">
                            <xs:enumeration value="1"/>
                            <xs:enumeration value="2"/>
                            <xs:enumeration value="3"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:attribute>
                <xs:attribute name="term" use="required">
                    <xs:simpleType>
                        <xs:restriction base="xs:string">
                            <xs:pattern value="(WS|SS)[0-9]{2}"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:attribute>
                <xs:attribute name="type" type="xs:string" use="required"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
    
    <xs:complexType name="simple">
        <xs:simpleContent>
            <xs:restriction base="tns:gradeType">
                <xs:enumeration value="1.0"/>
                <xs:enumeration value="1.3"/>
                <xs:enumeration value="1.7"/>
                <xs:enumeration value="2.0"/>
                <xs:enumeration value="2.3"/>
                <xs:enumeration value="2.7"/>
                <xs:enumeration value="3.0"/>
                <xs:enumeration value="3.3"/>
                <xs:enumeration value="3.7"/>
                <xs:enumeration value="4.0"/>
                <xs:enumeration value="4.7"/>
                <xs:enumeration value="5.0"/>
            </xs:restriction>
        </xs:simpleContent>
    </xs:complexType>
    
    <xs:complexType name="complex">
        <xs:simpleContent>
            <xs:restriction base="tns:gradeType">
                <xs:minInclusive value="1.0"/>
                <xs:maxInclusive value="5.0"/>
            </xs:restriction>
        </xs:simpleContent>
    </xs:complexType>
    

    就是这样。剩下的唯一事情就是让我弄清楚如何将我的属性包含在 grade 元素中,而不是包含在 gradeType 中,因为这会导致(至少对我来说有些未知原因)到我在自己的答案开头描述的问题。

    【讨论】:

    • 你发布的太酷了。
    • 再次感谢您的帮助。 :)
    【解决方案2】:

    难道你只想要union datatype?

    <xs:simpleType name="gradeType">
        <xs:union memberTypes="tns:simple tns:complex"/>
    </xs:simpleType>
    

    (未测试。)

    这应该允许您将tns:simple 或tns:complex 类型的值用作tns:gradeType。

    联合数据类型的值空间和词法空间是其成员类型的值空间和词法空间的联合。

    请参阅here 中的相关示例(无法复制,因为不确定许可证)。

    还可以考虑在tns:simple 中使用xs:enumeration 而不是xs:pattern。

    【讨论】:

    • 应用您的建议时,我的每个等级元素都出现错误:“简单”(或分别为“复杂”)不是联合类型“等级类型”的有效类型。元素“grade”上的属性“type”的值“simple”(或分别为“complex”)对其类型“gradeType”无效。到目前为止,我设法在 Internet 上找到的所有示例(包括您发布的链接)以及我知道工会的工作方式都应该可以正常工作。我想知道我做错了什么。
    • @rbaleksandar 那么,你为什么不问另一个问题,然后发布一个最小的复制示例呢?这里有很多合格的人来发现问题。
    • 我已经编辑了我的问题以包含一个完整的简约 XML 架构。至于“你为什么不问另一个问题”,我仍然认为联合问题是我最初问题中描述的这个问题的一部分。
    • @rbaleksandar 请发布示例 XML。现在我认为你在某处有一个sample,而不是像1.0这样的值。
    • 我现在知道你的意思,但我不知道如何调整我的架构。请参阅我添加的示例。这就是我想象的样子。由于 XSD 不支持 if 语句(如在 XSLT 中),我不知道我的 'gradeType' 衍生物如何控制 'grade' 元素的值。
    猜你喜欢
    • 2023-03-11
    • 2021-12-14
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 2021-08-11
    • 2010-12-13
    相关资源
    最近更新 更多