Alternative enumerations
Alternative enumerations (a co-constraint use case)
Make the set of enumerated values legal for one attribute depend on the value of a second attribute.
Cf. Enumeration or any string.
source: Fabio Vitali
Other use cases: Co-constraint Use Cases
Description
Multiple keywords can take terms from different dictionaries. Dictionaries are partially overlapping, so some but not all terms are present in more than one dictionary. It is an error to indicate a term that does not belong to the specified dictionary.
<keywords> <keyword dict="dict1" term="term1"/> <keyword dict="dict2" term="term1"/> ... </keywords>
(Elaboration by MSM:) To make a more concrete task for the sample
solutions, let us imagine that we have three dictionaries for color
names, each with an enumerated list of legal values. The dictionaries
and their enumerations are:
- html4.0: {aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, yellow}.g
- browsers: {AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan, DarkGoldenRod, DarkGray, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, Darkorange, DarkOrchid, DarkRed, DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue, DimGray, DodgerBlue, Feldspar, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod, Gray, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGrey, LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateBlue, LightSlateGray, LightSteelBlue, LightYellow, Lime, LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue, MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, Red, RosyBrown, RoyalBlue, SaddleBrown, Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, VioletRed, Wheat, White, WhiteSmoke, Yellow, YellowGreen}
- x11: {AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan, DarkGoldenrod, DarkGray, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue, DimGray, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, Goldenrod, Gray, Green, GreenYellow, Honeydew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenrodYellow, LightGreen, LightGrey, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSteelBlue, LightYellow, Lime, LimeGreen, Linen, Magenta, Maroon, MediumAquamarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue, MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenrod, PaleGreen, PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, Red, RosyBrown, RoyalBlue, SaddleBrown, Salmon, SandyBrown, SeaGreen, Seashell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen}
Note that the 'browser' list (taken from http://www.w3schools.com/html/html_colornames.asp) and the X11 list (from http://en.wikipedia.org/wiki/X11_Color_Names) are not completely identical: there are case differences in some tokens, and the browser list has three items which do not appear in the X11 list.
The requirement is that the value of the term attribute should come from the list associated with the dictionary named in the dict attribute.
Analysis
(Add your analysis here; see your name in pixels!)
Paul Biron
This is soluble by current means.
Assume types my:html40_color, my:defacto_color, X11_color, defined as shown in the SchemaPath description below. Define a union of these types:
<xsd:simpleType> <xsd:union memberTypes="my:html40_colors my:X11_colors my:defacto_colors"/> </xsd:simpleType>
and use xsi:type instead of dict.
Possible solutions
Relax NG
Grammaticalization
This can be handled by Relax-style grammaticalization, although some may find the formulation a little fiddly. To keep the main declarations short, we first define three different types for the three dictionaries; each type has a single token in its value space:
<xsd:simpleType name="html40_dictionary"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="html40"> <xsd:annotation> <xsd:documentation>Names defined in HTML 4.0</xsd:documentation> </xsd:annotation> </xsd:enumeration> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="X11_dictionary"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="x11"> <xsd:annotation> <xsd:documentation>Names defined by X11</xsd:documentation> </xsd:annotation> </xsd:enumeration> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="defacto_dictionary"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="browsers"> <xsd:annotation> <xsd:documentation>Names widely supported in browsers</xsd:documentation> </xsd:annotation> </xsd:enumeration> </xsd:restriction> </xsd:simpleType>
Now the declaration of the element uses a simple choice.
<xsd:element name="keyword"> <xsd:complexType> <xsd:choice> <xsd:sequence> <xsd:attribute name="dict" type="my:html40_dictionary"/> <xsd:attribute name="term" type="my:html40_color"/> </xsd:sequence> <xsd:sequence> <xsd:attribute name="dict" type="my:X11_dictionary"/> <xsd:attribute name="term" type="my:X11_color"/> </xsd:sequence> <xsd:sequence> <xsd:attribute name="dict" type="my:defacto_dictionary"/> <xsd:attribute name="term" type="my:defacto_color"/> </xsd:sequence> </xsd:choice> </xsd:complexType> </xsd:element>
Schematron
Check clause
One possible check-clause solution is the following. Note that the enumeration information has moved out of the type system and into the check clause.
For clarity, the middle of the two long lists has been elided.
<xsd:complexType> <xsd:annotation><xsd:appinfo> <sch:pattern><sch:rule> <sch:report test=" (@dict='html40' and not(contains(' aqua black blue fuchsia gray green lime maroon - navy olive purple red silver teal white yellow ', concat(' ',@term,' ')))) ">If @dict is 'html40', then @term must be one of aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, or yellow.</sch:report> <sch:report test=" (@dict='browsers' and not(contains(' AliceBlue AntiqueWhite Aqua Aquamarine Azure - Beige Bisque Black BlanchedAlmond Blue BlueViolet - ... Snow SpringGreen SteelBlue Tan Teal Thistle Tomato Turquoise - Violet VioletRed Wheat White WhiteSmoke Yellow YellowGreen ', concat(' ',@term,' ')))) ">If @dict is 'browsers', then @term must be one of the names defined by the 'browsers' list (see the documentation).</sch:report> <sch:report test=" (@dict='x11' and not(contains(' AliceBlue AntiqueWhite Aqua Aquamarine Azure - Beige Bisque Black BlanchedAlmond Blue BlueViolet - ... SteelBlue Tan Teal Thistle Tomato Turquoise Violet - Wheat White WhiteSmoke Yellow YellowGreen ', concat(' ',@term,' ')))) ">If @dict is 'x11, then @term must be one of the names defined by X11 (see the documentation for full list).</sch:report> </sch:rule></sch:pattern> </xsd:appinfo></xsd:annotation> <xsd:attribute name="term" type="xsd:NCName"/> <xsd:attribute name="dict"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="html40"> <xsd:annotation> <xsd:documentation>Names defined in HTML 4.0</xsd:documentation> </xsd:annotation> </xsd:enumeration> <xsd:enumeration value="browsers"> <xsd:annotation> <xsd:documentation>Names widely supported in browsers</xsd:documentation> </xsd:annotation> </xsd:enumeration> <xsd:enumeration value="x11"> <xsd:annotation> <xsd:documentation>Names defined by X11</xsd:documentation> </xsd:annotation> </xsd:enumeration> </xsd:restriction> </xsd:simpleType> </xsd:attribute>
(Solution offered by MSM)
SchemaPath
One possible SchemaPath solution to this is as follows. First, define an enumerated set of values for the dictionary names:
<xsd:simpleType name="color_dictionaries"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="html40"> <xsd:annotation> <xsd:documentation>Names defined in HTML 4.0</xsd:documentation> </xsd:annotation> </xsd:enumeration> <xsd:enumeration value="browsers"> <xsd:annotation> <xsd:documentation>Names widely supported in browsers</xsd:documentation> </xsd:annotation> </xsd:enumeration> <xsd:enumeration value="x11"> <xsd:annotation> <xsd:documentation>Names defined by X11</xsd:documentation> </xsd:annotation> </xsd:enumeration> </xsd:restriction> </xsd:simpleType>
Then define three enumerations of the color terms available in each
dictionary (the lists are abbreviated here for obvious reasons):
<xsd:simpleType name="html40_color"> <xsd:restriction base="xsd:NCName"> <xsd:enumeration value="aqua"/> <xsd:enumeration value="black"/> ... <xsd:enumeration value="white"/> <xsd:enumeration value="yellow"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="defacto_color"> <xsd:restriction base="xsd:NCName"> <xsd:enumeration value="AliceBlue"/> <xsd:enumeration value="AntiqueWhite"/> ... <xsd:enumeration value="DodgerBlue"/> <xsd:enumeration value="Feldspar"/> <xsd:enumeration value="FireBrick"/> ... <xsd:enumeration value="White"/> <xsd:enumeration value="WhiteSmoke"/> <xsd:enumeration value="Yellow"/> <xsd:enumeration value="YellowGreen"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="X11_color"> <xsd:restriction base="xsd:NCName"> <xsd:enumeration value="AliceBlue"/> <xsd:enumeration value="AntiqueWhite"/> ... <xsd:enumeration value="DodgerBlue"/> <xsd:enumeration value="FireBrick"/> ... <xsd:enumeration value="White"/> <xsd:enumeration value="WhiteSmoke"/> <xsd:enumeration value="Yellow"/> <xsd:enumeration value="YellowGreen"/> </xsd:restriction> </xsd:simpleType>
Finally, define the keyword element using a complex type in
which the type assigned to the term attribute is conditional
on the value of the dict attribute:
<xsd:element name="keyword"> <xsd:complexType> <xsd:sequence/> <xsd:attribute name="dict" type="my:color_dictionaries"/> <xsd:attribute name="term"> <xsd:alt cond="../@dict='html40'" type="html40_color"/> <xsd:alt cond="../@dict='browsers'" type="defacto_color"/> <xsd:alt cond="../@dict='x11'" type="X11_color"/> </xsd:attribute> </xsd:complexType> </xsd:element>
A second SchemaPath solution would be essentially the same
as the check clause solution: define keyword with a
loose type, use an XPath expression to
capture the condition "If dict = "`html40`", then
term must be one of ... and if dict = "`browsers`"
then term must be one of ... and if dict = "`x11`"
then term must be one of ...", and if the condition is
not met, then conditionally assign the type `xsd:error`
to the keyword element.
(Solutions proposed by MSM)