如何高效地在XML中建模逻辑/布尔表达式?

3

这里有一个小的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>

你会如何处理这个问题?
4个回答

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) 是相同的。
此外,可以添加不止两个信号。

对于 ><,左右的位置是很重要的。在我看来,能够“分组”多个信号是一个不错的便利功能,但它们仍然需要两两处理。 - marsze

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>


返回一个漂亮的一致和可嵌套的文本。 - marathon
2
你可以使用一个type属性(例如type="or"等)来代替冒号(:)。 - Armatus

1

你的第一个“快速尝试”在我看来非常合理,除了外部的“expr”元素可能没有太多价值。


0

看看微软.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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接