Search code examples
xmlxsdassertcomplextype

XML more specific validation through xsd assert


this is an schema that i need to improve to validate by an assert that if rule/type has a value of A or B then Return = true in something like:

<xsd:assert test="if (@type$value = A or @type$value= B) then @return$value = true" />

this is the XSD that I already have been working :

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:simpleType name="Rule">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="A"/>
        <xsd:enumeration value="B"/>
        <xsd:enumeration value="C"/>
        <xsd:enumeration value="D"/>
        <xsd:enumeration value="E"/>
    </xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="cType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="C-val1"/>
        <xsd:enumeration value="C-val2"/>
        <xsd:enumeration value="C-val3"/>
    </xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="DType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="D-val1"/>
        <xsd:enumeration value="D-val2"/>
        <xsd:enumeration value="D-val3"/>
    </xsd:restriction>
</xsd:simpleType>
<xsd:element name="Rule">
    <xsd:complexType>
        <xsd:complexContent>
            <xsd:restriction base="xsd:anyType">
                <xsd:sequence>
                    <xsd:element name="Type" type="Rule"/>
                    <xsd:element name="Return" type="xsd:boolean"/>
                    <xsd:choice>
                        <xsd:element name="BConfig"/>
                        <xsd:element name="AConfig"/>
                        <xsd:element name="CConfig" type="CRule"/>
                        <xsd:element name="DConfig" type="DRule"/>
                        <xsd:element name="EElement" type="xsd:integer"/>
                    </xsd:choice>
                </xsd:sequence>
            </xsd:restriction>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:element>
<xsd:complexType name="CRule">
    <xsd:complexContent>
        <xsd:restriction base="xsd:anyType">
            <xsd:sequence>
                <xsd:element name="C" type="CType" maxOccurs="3" />
            </xsd:sequence>
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="DRule">
    <xsd:complexContent>
        <xsd:restriction base="xsd:anyType">
            <xsd:sequence>
                <xsd:element name="D" type="DType" maxOccurs="3" />
            </xsd:sequence>
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>

But don't know how to use asset correctly

UPDATE 1:

following sergiofc this is the updated schema

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:simpleType name="Rule">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="A"/>
        <xsd:enumeration value="B"/>
        <xsd:enumeration value="C"/>
        <xsd:enumeration value="D"/>
        <xsd:enumeration value="E"/>
    </xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="cType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="C-val1"/>
        <xsd:enumeration value="C-val2"/>
        <xsd:enumeration value="C-val3"/>
    </xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="DType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="D-val1"/>
        <xsd:enumeration value="D-val2"/>
        <xsd:enumeration value="D-val3"/>
    </xsd:restriction>
</xsd:simpleType>
<xsd:element name="Rule">
    <xsd:complexType>
        <xsd:complexContent>
            <xsd:restriction base="xsd:anyType">
                <xsd:sequence>
                    <xsd:element name="Type" type="Rule"/>
                    <xsd:element name="Return" type="xsd:boolean"/>
                    <xsd:choice>
                        <xsd:element name="BConfig"/>
                        <xsd:element name="AConfig"/>
                        <xsd:element name="CConfig" type="CRule"/>
                        <xsd:element name="DConfig" type="DRule"/>
                        <xsd:element name="EElement" type="xsd:integer"/>
                    </xsd:choice>
                </xsd:sequence>
                <xsd:assert test="if (Type = ('A', 'B')) then Return = true() else true()"/>
            </xsd:restriction>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:element>
<xsd:complexType name="CRule">
    <xsd:complexContent>
        <xsd:restriction base="xsd:anyType">
            <xsd:sequence>
                <xsd:element name="C" type="CType" maxOccurs="3" />
            </xsd:sequence>
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="DRule">
    <xsd:complexContent>
        <xsd:restriction base="xsd:anyType">
            <xsd:sequence>
                <xsd:element name="D" type="DType" maxOccurs="3" />
            </xsd:sequence>
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>

but i still don't know where to locate the xsd:assert, i'm still getting the same error.


Solution

  • If I understand well you want Return value to be true if Type value is A or B. If so, you can use this assertion:

    <xsd:assert test="if (Type = ('A', 'B')) then Return = true() else true()"/>
    

    Explanation:

    1. You should only use @name to get an attribute named name, you must not use @ if you are selecting an element, name is enoug to select an element named name.
    2. $value is a variable that is only present in <xs:assertion> for simple values, it is not present in <xs:assert>.
    3. In XPath an expression like 'val2' = ('val1', 'val2', 'val3') returns true if some element in the left is present in the right sequence., although your or approach is also valid.

    If you wish, you can read XPath specs or an XPath tutorial to gain better knowledge of it.