IF...THEN...ELSE using XML
I have a program that uses XML formatted rules to create executable code for run-time. I have to define some actions and logical constructs using my own dialect. I have OR, AND, and NOT constructs and now I need to implement IF..THEN..ELSE.
I'm trying to come up with a syntax that would make sense and here's what I have so far:
<IF id='if-1'>
&开发者_如何转开发lt;TIME from="5pm" to="9pm" />
</IF>
<THEN id='if-1'>
<...some actions defined.../>
</THEN>
<ELSE id='if-1'>
<...other set of actions defined here.../>
</ELSE>
If looks difficult to read to me, but I don't see a cleaner way to represent this without doing too much nesting. Does anyone have a suggestion? (not using XML is not an option at this point in time :) )
Perhaps another way to code conditional constructs in XML:
<rule>
<if>
<conditions>
<condition var="something" operator=">">400</condition>
<!-- more conditions possible -->
</conditions>
<statements>
<!-- do something -->
</statements>
</if>
<elseif>
<conditions></conditions>
<statements></statements>
</elseif>
<else>
<statements></statements>
</else>
</rule>
I personally think that the if/then/else needs to be linked somehow.
<IF something>
<some actions>
<THEN something>
<some actions>
</THEN>
<ELSE something>
<some actions>
</ELSE>
</IF>
Faced with a similar problem sometime ago, I decided to go for a generalized "switch ... case ... break ... default" type solution together with an arm-style instruction set with conditional execution. A custom interpreter using a nesting stack was used to parse these "programs". This solution completely avoids id's or labels. All my XML language elements or "instructions" support a "condition" attribute which if not present or if it evaluates to true then the element's instruction is executed. If there is an "exit" attribute evaluating to true and the condition is also true, then the following group of elements/instructions at the same nesting level will neither be evaluated nor executed and the execution will continue with the next element/instruction at the parent level. If there is no "exit" or it evaluates to false, then the program will proceed with the next element/instruction. For example you can write this type of program (it will be useful to provide a noop "statement" and a mechanism/instruction to assign values and/or expressions to "variables" will prove very handy):
<ins-1>
<ins-11 condition="expr-a" exit="true">
<ins-111 />
...
</ins11>
<ins-12 condition="expr-b" exit="true" />
<ins-13 condition="expr-c" />
<ins-14>
...
</ins14>
</ins-1>
<ins-2>
...
</ins-2>
If expr-a is true then the execution sequence will be:
ins-1
ins-11
ins-111
ins-2
if expr-a is false and expr-b is true then it will be:
ins-1
ins-12
ins-2
If both expr-a and expr-b are false then we'll have:
ins-1
ins-13 (only if expr-c evaluates to true)
ins-14
ins-2
PS. I used "exit" instead of "break" because I used "break" to implement "breakpoints". Such programs are very hard to debug without some kind of breakpointing/tracing mechanism.
PS2. Because I had similar date-time conditions as your example along with the other types of conditions, I also implemented two special attributes: "from" and "until", that also had to evaluate to true if present, just like "condition", and which used special fast date-time checking logic.
I don't think you can design the if-then-else construct without taking the design for other constructs into account. I think it's a good principle that each expression should be an element, and its subexpressions should be child elements. There are then questions about whether the name of an element should reflect the type of expression it is, or its role relative to the parent. Or you can do both:
<if>
<condition>
<equals>
<number>2</number>
<number>3</number>
<equals>
<condition>
<then>
<string>Mary</string>
</then>
<else>
<concat>
<string>John</string>
<string>Smith</string>
</concat>
</else>
</if>
But you can sometimes get away with a design that omits the role-names (condition, then else) and relies on positional significance of elements relative to their parent. It depends a bit on how much you want to keep it concise.
<IF id='if-1'>
<CONDITION>
<TIME from="5pm" to="9pm" />
</CONDITION>
<THEN>
<...some actions defined.../>
</THEN>
<ELSE>
<...other set of actions defined here.../>
</ELSE>
</IF>
Seems easier to read to me. There's more nesting, but if anything that helps with the readability?
I think that the thing you must keep in mind is that your XML is being processed by a machine, not a human, so it only needs to be readable for the machine.
In other words, I think you should use whatever XML schema you need to make parsing/processing the rules as efficient as possible at run time.
As far as your current schema goes, I think that the id
attribute should be unique per element, so perhaps you should use a different attribute to capture the relationship among your IF
, THEN
, and ELSE
elements.
<IF id="if-1">
<TIME from="5pm" to="9pm" />
<ELSE>
<something else />
</ELSE>
</IF>
I don't know if this makes any sense to anyone else or it is actually usable in your program, but I would do it like this.
My point of view: You need to have everything related to your "IF" inside your IF-tag, otherwise you won't know what ELSE belongs to what IF. Secondly, I'd skip the THEN tag because it always follows an IF.
Personally, I would prefer
<IF>
<TIME from="5pm" to="9pm" />
<THEN>
<!-- action -->
</THEN>
<ELSE>
<!-- action -->
</ELSE>
</IF>
In this way you don't need an id
attribute to tie together the IF
, THEN
, ELSE
tags
<IF>
<CONDITIONS>
<CONDITION field="time" from="5pm" to="9pm"></CONDITION>
</CONDITIONS>
<RESULTS><...some actions defined.../></RESULTS>
<ELSE>
<RESULTS><...some other actions defined.../></RESULTS>
</ELSE>
</IF>
Here's my take on it. This will allow you to have multiple conditions.
精彩评论