这里的小xml建模练习。
假设我们有一些逻辑表达式: (x& y)| (p& q)
并且无论出于何种原因,都需要用XML表示。
这是一个快速刺,但我认为这很笨:
<expr>
<or>
<and>
<e>x</e>
<e>y</e>
</and>
<and>
<e>p</e>
<e>q</e>
</and>
</or>
</expr>
另一种刺痛,对我来说没有味道:
<expr>
<or>
<and l="x" r="y"/>
<and l="p" r="q"/>
</or>
</expr>
你会怎么做?
答案 0 :(得分:5)
Armatus的回答对我来说很好看。我认为左右元素是多余的。有一个逻辑表达式,如果我左右或左右评估它们并不重要。
<expr type="or">
<expr type="and">
<sig>x</sig>
<sig>y</sig>
</expr>
<expr type="and">
<sig>p</sig>
<sig>q</sig>
</expr>
</expr>
例如:
(x & y) | (p & q)
与(q & p) | (y & x)
此外,它可以添加两个以上的信号。
答案 1 :(得分:4)
这个怎么样?
<expr:or>
<l>
<expr:and>
<l>x</l><r>y</r>
</expr>
</l>
<r>
<expr:and>
<l>p</l><r>q</r>
</expr>
</r>
</expr>
还可以添加<expr:xor><l>x</l><r>y</r></expr>
和<expr:not>x</expr>
。
答案 2 :(得分:1)
你的第一个“快速刺”对我来说看起来非常合理,除了外部'expr'元素,它不会增加太多价值。
答案 3 :(得分:0)
看看在Microsoft .NET的System.Linq.Expressions名称空间中如何建模表达式树是很有趣的。我认为在这里很重要的基本概念是,所有内容都继承自基本的Expression类-几乎所有内容都是表达式,可以是二进制运算,参数,常量等。>
此外,NuGet软件包Serialize.Linq演示了如何将这样的表达式树序列化为XML。
长期解决方案
尽管这仅供参考。我认为XML模型可以变得更简单。我会像这样为您的示例建模:
<expr returns="boolean">
<params>
<param name="x" type="boolean">
<param name="y" type="boolean">
<param name="p" type="boolean">
<param name="q" type="boolean">
</params>
<body op="bor">
<left op="band">
<left op="param">x</left>
<right op="param">y</left>
</left>
<right op="band">
<left op="param">p</left>
<right op="param">q</left>
</right>
</body>
<expr>
简短解决方案
根据您的实现,您也许可以省略<params>
元素和type
属性,并在解释表达式时以更“隐式”的方式处理这些事情(类似于JavaScript,PowerShell ,...)。另外,如果XML输出的大小/长度成问题,则可以使元素和类型的名称更短。
因此,这是高度简化版本的和示例:
<e t="bor">
<l t="band">
<l t="prm">x</l>
<r t="prm">y</r>
</l>
<r t="band">
<l t="prm">p</l>
<r t="prm">y</r>
</r>
</e>
另一个示例
为了完整起见,这是另一个示例,说明如何以这种方式对更复杂的表达式进行建模。
伪代码lambda /箭头表达式:
(float b, int e) => e == 0 ? 1 : (e == 1 ? b : pow(b, e))
XML表示形式
<expr returns="float">
<params>
<prm name="b" type="float" />
<prm name="e" type="int" />
</params>
<body op="if">
<cond op="eq">
<left op="param">e</left>
<right op="const" type="int">0</right>
</cond>
<true op="const" type="float">1</true>
<false op="if">
<cond op="eq">
<left op="param">e</left>
<right op="const" type="int">1</right>
</cond>
<true op="param">b</true>
<false op="call" name="pow">
<args>
<arg op="param">p</arg>
<arg op="param">e</arg>
</args>
</false>
</false>
</body>
</expr>