Photo from Chile

ValidateThis! - Less Verbose XML

I was creating an XML schema definition for my current XML schema and I realized that I could make it much less verbose. I could eliminate most of the "container" elements, such as rules and params and it wouldn't affect its readability or parseability, and would save me some typing when creating the XML files, so I've done that.

For the record, here is the new sample XML file:

view plain print about
1<?xml version="1.0" encoding="UTF-8"?>
2<validateThis xsi:noNamespaceSchemaLocation="validateThis.xsd"
3    xmlns:xsi="">

4    <objectProperties>
5        <property name="UserName" desc="Email Address">
6            <rule type="required" contexts="Register,Update" />
7            <rule type="email" contexts="Register,Update"
8                failureMessage="Hey, buddy, you call that an Email Address?" />

9        </property>
10        <property name="Nickname">
11            <rule type="custom" contexts="Register,Update">
12                <param methodname="CheckDupNickname" />
13            </rule>
14        </property>
15        <property name="UserPass" desc="Password">
16            <rule type="required" contexts="Register,Update" />
17            <rule type="rangelength" contexts="Register,Update">
18                <param minlength="5" />
19                <param maxlength="10" />
20            </rule>
21            <rule type="equalTo" contexts="Register,Update">
22                <param ComparePropertyName="VerifyPassword" />
23            </rule>
24        </property>
25        <property name="VerifyPassword" desc="Verify Password">
26            <rule type="required" contexts="Register,Update" />
27        </property>
28        <property name="FirstName" desc="First Name">
29            <rule type="required" contexts="Update" />
30        </property>
31        <property name="LastName" desc="Last Name">
32            <rule type="required" contexts="Update" />
33            <rule type="required" contexts="Register">
34                <param DependentPropertyName="FirstName" />
35            </rule>
36        </property>
37        <property name="LikeOther" desc="What do you like?">
38            <rule type="required" contexts="Register,Update"
39                failureMessage="If you don't like Cheese and you don't like Chocolate, you must like something!">

40                <param ServerCondition="getLikeCheese() EQ 0 AND getLikeChocolate() EQ 0" />
41                <param ClientCondition="$(&quot;[name='LikeCheese']&quot;).getValue() == 0 &amp;&amp; $(&quot;[name='LikeChocolate']&quot;).getValue() == 0;" />
42            </rule>
43        </property>
44        <property name="HowMuch" desc="How much money would you like?">
45            <rule type="numeric" contexts="Register,Update" />
46        </property>
47        <property name="AllowCommunication" desc="Allow Communication" />
48        <property name="CommunicationMethod" desc="Communication Method">
49            <rule type="required" contexts="Register,Update"
50                failureMessage="If you are allowing communication, you must choose a communication method.">

51                <param DependentPropertyName="AllowCommunication" />
52                <param DependentPropertyValue="1" />
53            </rule>
54        </property>
55    </objectProperties>

And here's the xsd, without the annotations that I've since added to it:

view plain print about
1<xs:schema xmlns:xs="">
2    <xs:element name="validateThis">
3        <xs:complexType>
4            <xs:sequence>
5                <xs:element name="objectProperties">
6                    <xs:complexType>
7                        <xs:sequence>
8                            <xs:element
9                                maxOccurs="unbounded"
10                                name="property">

11                                <xs:complexType>
12                                    <xs:sequence>
13                                        <xs:element
14                                            minOccurs="0"
15                                            maxOccurs="unbounded"
16                                            name="rule">

17                                            <xs:complexType>
18                                                <xs:sequence>
19                                                    <xs:element
20                                                        minOccurs="0"
21                                                        maxOccurs="unbounded"
22                                                        name="param">

23                                                        <xs:complexType>
24                                                            <xs:anyAttribute
25                                                                namespace="##any"
26                                                                processContents="lax"/>

27                                                        </xs:complexType>
28                                                    </xs:element>
29                                                </xs:sequence>
30                                                <xs:attribute
31                                                    name="type"
32                                                    type="xs:string"
33                                                    use="required"/>

34                                                <xs:attribute
35                                                    name="contexts"
36                                                    type="xs:string"
37                                                    use="optional"/>

38                                                <xs:attribute
39                                                    name="failureMessage"
40                                                    type="xs:string"
41                                                    use="optional"/>

42                                            </xs:complexType>
43                                        </xs:element>
44                                    </xs:sequence>
45                                    <xs:attribute
46                                        name="name"
47                                        type="xs:string"
48                                        use="required"/>

49                                    <xs:attribute
50                                        name="desc"
51                                        type="xs:string"
52                                        use="optional"/>

53                                </xs:complexType>
54                            </xs:element>
55                        </xs:sequence>
56                    </xs:complexType>
57                </xs:element>
58            </xs:sequence>
59        </xs:complexType>
60    </xs:element>

When doing your XSD, I would recommend putting in the <xs:annotation><xs:documentation>this does stuff</xs:documentation></xs:annotation> elements.

That way, when you are using your favourite XML editor, you shoud get inline help on exactly what each element and attribute does.

You can see examples of this in the Transfer XSD's.
# Posted By Mark Mandel | 10/19/08 8:16 PM
Thanks Mark. I actually have added annotations to the xsd, but didn't want to crowd the blog posting with them, so I included a version of the xsd without annotations.

How did I know to add them, you might ask? By looking at transfer.xsd, of course! It was an excellent reference to use while creating my own schema.
# Posted By Bob Silverberg | 10/20/08 5:34 AM

I've been enjoying your Transfer and Validation posts a lot, thanks for blogging on these topics.

I really like where you're going with your validation system, it definitely matches my mental model for how to develop a flexible validation solution. Have you thought about implementing validation-inheritance or declaratively binding a form submission to a validation definition (to promote DRY principles)? I'd be interested in hearing your thoughts on some of these "features". I have described these features with some sample markup on Ben Nadel's blog during another validation discussion. If you read my comment, what I said above will probably make more sense :)

Thanks again for sharing your thoughts and techniques with all of us!
# Posted By Kurt Bonnet | 10/20/08 12:08 PM

I just read through that post and your comments. It's the first time I've read it and it's amazing how similar our requirements are ;-) Regarding the two "features" that you mention:

I understand what you're getting at with the validation inheritance scenario. There is nothing "baked in" right now that would implement that, but it wouldn't be that difficult to add. I see that as a bit of an edge case currently, so I don't think I'll add it before releasing the code, but if turns out that people are interested in using the code, and it's a feature people want, I'll consider adding it.

Regarding the formValidations thing, I believe that this requirement is met by the context attribute. I realize that I didn't cover that in any great detail, but basically it allows you to define the context in which the rule should apply to the business object. You can, if you wish, equate context with form, and I think it would give you what you want.

Have I addressed your questions?
# Posted By Bob Silverberg | 10/20/08 2:22 PM