Child type redefines only one element from parent type

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-12 02:47:16

问题


In a XSD file, a want to define:

  • a parent type (that contains 10 nodes).
  • a 7 child types (each child type contains the same 10 nodes, but the type of the 2nd node is different).

It can be done by defining the child types by restriction on the parent type (the parent type will be the base type for the child types). The problem: In child types, I have to write again all the nodes of the parent type (not only the 2nd node). The question: Can I write only the node that I'm overriding (the 2nd node)?

Example: If I define the following parent type:

<xs:complexType name="Parent">
    <xs:sequence>
        <xs:element name="Node1" type="type1" />
        <xs:element name="Node2" type="type2" />
        <xs:element name="Node3" type="type3" />
        ...
        <xs:element name="Node10" type="type10" />
    </xs:sequence>
</xs:complexType>

then I have to define the childs by restriction on the parent:

<xs:complexType name="Child1">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:element name="Node1" type="type1" />
                <xs:element name="Node2" type="type2_derived_1" />
                <xs:element name="Node3" type="type3" />
                ...
                <xs:element name="Node10" type="type10" />
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

<xs:complexType name="Child2">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:element name="Node1" type="type1" />
                <xs:element name="Node2" type="type2_derived_2" />
                <xs:element name="Node3" type="type3" />
                ...
                <xs:element name="Node10" type="type10" />
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

...
(same for all the 10 childs)

That is a lot of writting and DUPLICATED code (for each child, I have to write AGAIN all the original nodes, that are already at the parent). I would prefer to write only the node that I am overriding, something like this:

<xs:complexType name="Child1">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:changed>
                <xs:element name="Node2" type="type2_derived_1" />
            </xs:changed>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

<xs:complexType name="Child2">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:changed>
                <xs:element name="Node2" type="type2_derived_2" />
            </xs:changed>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

...
(same for all the 10 childs)

Is there some way to avoid the duplication of code? I'm using XSD 1.1, so I can use all of its advanced features.

I know I can use extension instead of restriction: For example, I could exclude the 2nd node from the parent type, and add it by extension at the childs. But, in that case, it wouldn't be the 2nd node, it would be the 10th node. I want to redefine (or to add) the 2nd node at the childs.


Update: Solved: I like the workaround given by Sperberg-McQueen: Model groups. A model group is like a macro in C, its content is expanded. So I can define a model group for nodes before the changed node, and other model group for nodes after it. For example:

<xs:group name="g_node_1">
    <xs:sequence>
        <xs:element name="Node1" type="type1"/>
    </xs:sequence>
</xs:group>

<xs:group name="g_nodes_3to10">
    <xs:sequence>
        <xs:element name="Node3" type="type3"/>
        <xs:element name="Node4" type="type4"/>
        <xs:element name="Node5" type="type5"/>
        <xs:element name="Node6" type="type6"/>
        <xs:element name="Node7" type="type7"/>
        <xs:element name="Node8" type="type8"/>
        <xs:element name="Node9" type="type9"/>
        <xs:element name="Node10" type="type10"/>
    </xs:sequence>
</xs:group>

<xs:complexType name="Parent">
    <xs:sequence>
        <xs:group ref="g_node_1"/>
        <xs:element name="Node2" type="type2"/>
        <xs:group ref="g_nodes_3to10"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="Child1">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:group ref="g_node_1"/>
                <xs:element name="Node2" type="type2_derived_1" />
                <xs:group ref="g_nodes_3to10"/>
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

<xs:complexType name="Child2">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:group ref="g_node_1"/>
                <xs:element name="Node2" type="type2_derived_2" />
                <xs:group ref="g_nodes_3to10"/>
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

It requires 2 more lines (per type) than the ideal solution, but it is better than nothing.


回答1:


There is no straightforward way to define the relations you want without repeating the content model. There are some possible workarounds.

One way to avoid the duplication: use general entities for the unchanging parts of the content model. (If you have the misfortune to be stuck using an XSD validator that doesn't support the use of DTDs for schema documents, you'll need to expand the entities using a tool like xmllint or rxp, or run an XSLT identity transform on the schema document, before feeding it to the validator.)

Another way: use named model groups for the unchanging parts of the content model.

A third way is sometimes possible, depending on how type2, type2_derived_1, type2_derived_2 etc. relate to each other: use assertions to force the second child into the shape you desire.



来源:https://stackoverflow.com/questions/24038492/child-type-redefines-only-one-element-from-parent-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!