[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
Example of lousy XML design
- From: "Costello, Roger L." <costello@mitre.org>
- To: "xml-dev@lists.xml.org" <xml-dev@lists.xml.org>
- Date: Sat, 3 Aug 2013 19:46:40 +0000
Hi Folks,
Below is an example of XML that looks on the surface to be well designed. However, when you go to implement applications to process the XML, then you realize that due to the way the XML has been designed it forces application code to be brittle and non-extensible.
Example: in an XML vocabulary that I am dealing with there is an element called Action. Its purpose is to, well, specify the action to be taken on something. The value of Action is text; specifically the value is one of these text values:
- Remove
- Replace
- Reject
- Modify
- Alert Management
- Call 911
Here is a sample usage:
<Action> Remove </Action>
That seems pretty darned straightforward. How can I possibly claim that it is bad XML design?
Well, I do claim that. In fact, I claim that it is horrible design.
Here is a typical application processing scenario for the data:
Create a module for each action. My programming language is XSLT, so I created an XSLT template rule for each action:
<xsl:template match="*" mode="Remove">
<xsl:template match="*" mode="Replace">
<xsl:template match="*" mode="Reject">
...
Next, I read in the value of Action and stored it into a variable, $action:
<xsl:variable name="action" select="//Action" />
Then I fired the appropriate template, based on the value of $action. The way to accomplish this is with a choose statement:
<xsl:choose>
<xsl:when test="$action eq 'Remove'">
<xsl:apply-templates select="." mode="Remove" />
</xsl:when>
<xsl:when test="$action eq 'Replace'">
<xsl:apply-templates select="." mode="Replace" />
</xsl:when>
<xsl:when test="$action eq 'Reject'">
<xsl:apply-templates select="." mode="Reject" />
</xsl:when>
...
</xsl:choose>
That is awful code. It is brittle and not extensible: if new values for Action are added or existing values are removed, then the code must be changed.
Time to scrap that XML design.
Let's redesign the XML.
I redesigned Action so that its value is any of these *elements*:
<Remove />
<Replace />
<Reject />
<Modify />
<Alert_Management />
<Call_911 />
That is a fundamental change. Instead of text content, Action now has element content.
Let's see how an application will implement the actions.
As before, I have a template for each Action:
<xsl:template match="Remove" mode="Act">
<xsl:template match="Replace" mode="Act">
<xsl:template match="Reject" mode="Act">
...
Now, however, each template rule matches one of the child *elements* of Action.
Firing the appropriate template rule requires just one statement:
<xsl:apply-templates select="$action" mode="Act" />
That code doesn't change even if new values for Action are added or existing values are removed. The code is robust and extensible.
The redesigned XML enables the creation of applications that are driven by the input, i.e., "data-driven code."
Lesson Learned: If an element's values will require application modules, one module for each value, then don't use enumeration lists. That is, don't design the XML like this:
<xs:element name="Action">
<xs:simpleType >
<xs:restriction base="xs:string">
<xs:enumeration value="Remove"/>
<xs:enumeration value="Replace"/>
<xs:enumeration value="Reject"/>
<xs:enumeration value="Modify"/>
<xs:enumeration value="Alert_Management"/>
<xs:enumeration value="Call_911"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Instead, design the XML like this:
<xs:element name="Action">
<xs:complexType >
<xs:sequence>
<xs:element name="Remove" type="empty" />
<xs:element name="Replace" type="empty" />
<xs:element name="Reject" type="empty" />
<xs:element name="Modify" type="empty"/>
<xs:element name="Alert_Management" type="empty" />
<xs:element name="Call_911" type="empty" />
</xs:sequence>
</xs:complexType>
</xs:element>
Comments?
/Roger
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]