Tomer Gabel's annoying spot on the 'net RSS 2.0
# Wednesday, 28 December 2005
I hate ugly hacks, but sometimes you're left with no choice. I was hacking away at the XML schema for one of our projects, and eventually settled on a neat solution. Imagine the following scenario: your system stores its configuration in XML format; the configuration defines several types of events that can occur, and all these events share the same actions. What's the most efficient way to go about it?

Borrowing a page from the object-oriented software design book, I decided to create an abstract BaseActionType. It will include some basic self-describing information (lets suppose I'd like to have an action category; I would simply add an element to the base type and override the value in each subclass.) Each subclass would describe a different type of action, for example a SendEmailActionType would extend BaseActionType, override its category with a fixed value and add fields such as server, subject etc.

Unfortunately, it appears that XML Schema only supports one of two modes of derivation: derive by extension or derive by restriction, whereas what I in fact require is a hybrid of the two. xs:extension will not allow you to override values, whereas xs:restriction will not allow you to define new elements. This is a problem I used to encounter all the time when creating XML schemas, and today it finally pissed me off enough to find a solution. I was really stumped for a while, but eventually noticed that one of the examples on the XML Schema specification was:

<xs:complexType name="length2">
 <xs:complexContent>
  <xs:restriction base="xs:anyType">
   <xs:sequence>
    <xs:element name="size" type="xs:nonNegativeInteger"/>
    <xs:element name="unit" type="xs:NMTOKEN"/>
   </xs:sequence>
  </xs:restriction>
 </xs:complexContent>
</xs:complexType>

It got me thinking: how can they be restricting a type while adding elements? Then it hit me - this is in fact a restriction on an xs:any particle! Here's the solution I came up with:

<xs:complexType name="BaseActionType">
 <xs:sequence>
  <xs:element name="Category" type="CategoryType" />
  <xs:any processContents="strict" minOccurs="0" maxOccurs="unbounded" />
 </xs:sequence>
</xs:complexType>

<xs:complexType name="EmailActionType">
 <xs:complexContent>
  <xs:restriction base="BaseActionType">
   <xs:element name="Category" fixed="Synchronous" />
   <xs:element name="Server" type="xs:string" />
   ...
  </xs:restriction>
 </xs:complexContent>
</xs:complexType>

I reckon developers who are more experienced with XML than I am already knew the answer, but since I've been using XML far more intensively than the average developer and was repeatedly stumped by the same problem I hope someone finds this useful.

Update (January 2nd, 10:26): My technological enthusiasm has an annoying tendency to turn into a display of naïveté. Specifically, the hack above seems to work just fine for Stylus Studio (any maybe other technologies, who knows?) -- but isn't really accepted by the .NET SDK xsd.exe tool. There are two issues here:

  • The tool fails to recognize fixed="value" attributes for enumerations ("Schema validation warning: Element's type does not allow fixed or default value constraint.")
  • The tool does not recognize restriction of xs:any ("Schema validation warning: Invalid particle derivation by restriction.")

I haven't been able to work around these limitations (yet), nor have I the time at the moment to research into XML Schema and find out if these features are supposed to be supported. In the meanwhile I'm reverting to another solution.

Wednesday, 28 December 2005 17:34:37 (Jerusalem Standard Time, UTC+02:00)  #    -
Development
Me!
Send mail to the author(s) Be afraid.
Archive
<2024 December>
SunMonTueWedThuFriSat
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
All Content © 2024, Tomer Gabel
Based on the Business theme for dasBlog created by Christoph De Baene (delarou)