Java中的动态嵌套逻辑处理

Java中的动态嵌套逻辑处理,java,nested,logical-operators,Java,Nested,Logical Operators,假设我有一个包含许多嵌套逻辑运算符的xml,类似于此结构: <?xml version="1.0" encoding="UTF-8"?> <Or> <And> <Condition1> <Condition2> </And> <Or> <And> <Condition3>

假设我有一个包含许多嵌套逻辑运算符的xml,类似于此结构:

<?xml version="1.0" encoding="UTF-8"?>
<Or>
    <And>
        <Condition1>
        <Condition2>
    </And>
    <Or>
        <And>
            <Condition3>
            <Condition4>
            <Or>
                <Condition5>
                <Condition6>
            </Or>
        </And>
        <Condition7>
    </Or>
    <Condition8>
</Or>

结构的长度或深度没有限制


我想用Java表示这个结构,并且能够在任何给定的时间确定根节点的布尔值。我能想到的唯一方法是某种嵌套列表安排,我正试图避免这种安排,因为我担心这可能会非常“混乱”。有更优雅的解决方案吗?

我在一个项目中遇到了类似的问题。我的解决方案是创建一个类型树,其中包含一个名为
value
的字段和一个名为
后代的树列表

当一个节点是一个操作符时,值将被操作符名(AND、OR、NOT)填充,子条件将被添加到子体列表中。当它是一个条件时,该值将包含该条件,并且列表将为空


类树还包含一个方法evaluate(boolean neutralElement),该方法返回一个布尔值。当评估节点时,如果它不是操作符,我只会评估它。如果它是一个运算符,我会将当前运算符应用于其子体(neutralElement是必需的,因为由于项目条件的原因,子体可能是空文本,如果其父体是或,则应将其计算为false;如果其父体是AND,则应将其计算为true)。

这是一个有趣的问题。在我看来,使用JAXB很容易解决这个问题。下面是一个小原型:

import java.io.StringReader;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;

import org.xml.sax.InputSource;

public class Test {
  public static void main(String... args) {
    String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
        "<Or>\r\n" +
        "  <And>\r\n" +
        "    <Condition value = 'true'/>\r\n" +
        "    <Condition value = 'true'/>\r\n" +
        "  </And>\r\n" +
        "  <And>\r\n" +
        "    <Condition value = 'false'/>\r\n" +
        "    <Condition value = 'true'/>\r\n" +
        "    <Or>\r\n" +
        "      <Condition value = 'false'/>\r\n" +
        "      <Condition value = 'true'/>\r\n" +
        "    </Or>\r\n" +
        "  </And>\r\n" +
        "  <Condition value = 'false'/>\r\n" +
        "  <Condition value = 'false'/>\r\n" +
        "</Or>";
    try {
      Evaluable o = (Evaluable) JAXBContext.newInstance(BooleanOperators.class, Condition.class).createUnmarshaller()
          .unmarshal(new InputSource(new StringReader(xml)));
      System.out.println(o);
      System.out.println(o.evaluate());
    } catch (JAXBException e) {
      e.printStackTrace();
    }
  }
}

interface Evaluable {
  static final Evaluable TRUE = of(true);
  static final Evaluable FALSE = of(false);

  boolean evaluate();

  static Evaluable of(boolean result) {
    return new Evaluable() {
      @Override
      public boolean evaluate() {
        return result;
      }
    };
  }
}

@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso({ And.class, Or.class })
abstract class BooleanOperators implements Evaluable {
  @XmlAnyElement(lax = true)
  protected List<Evaluable> evaluables;

  @Override
  public String toString() {
    return getClass().getSimpleName() + " {" + evaluables + "}";
  }
}

@XmlRootElement(name = "And")
@XmlAccessorType(XmlAccessType.NONE)
class And extends BooleanOperators {
  @Override
  public boolean evaluate() {
    if (evaluables == null || evaluables.isEmpty()) {
      return true;
    }
    return evaluables.stream().reduce(TRUE, (i, j) -> Evaluable.of(i.evaluate() && j.evaluate())).evaluate();
  }
}

@XmlRootElement(name = "Or")
@XmlAccessorType(XmlAccessType.NONE)
class Or extends BooleanOperators {
  @Override
  public boolean evaluate() {
    if (evaluables == null || evaluables.isEmpty()) {
      return true;
    }
    return evaluables.stream().reduce(FALSE, (i, j) -> Evaluable.of(i.evaluate() || j.evaluate())).evaluate();
  }
}

@XmlRootElement(name = "Condition")
@XmlAccessorType(XmlAccessType.NONE)
class Condition implements Evaluable {
  @XmlAttribute(required = true, name = "value")
  private boolean result;
  @Override
  public boolean evaluate() {
    return result;
  }

  @Override
  public String toString() {
    return "Condition (" + result + ")";
  }
}
导入java.io.StringReader;
导入java.util.List;
导入javax.xml.bind.JAXBContext;
导入javax.xml.bind.JAXBException;
导入javax.xml.bind.annotation.XmlAccessType;
导入javax.xml.bind.annotation.XmlAccessorType;
导入javax.xml.bind.annotation.xmlanyement;
导入javax.xml.bind.annotation.XmlAttribute;
导入javax.xml.bind.annotation.XmlRootElement;
导入javax.xml.bind.annotation.xmlsee;
导入org.xml.sax.InputSource;
公开课考试{
公共静态void main(字符串…参数){
字符串xml=“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
“\r\n”+
"";
试一试{
可评估的o=(可评估的)JAXBContext.newInstance(booleanporters.class,Condition.class).createUnmarshaller()
.unmarshal(新输入源(新StringReader(xml));
系统输出打印ln(o);
System.out.println(o.evaluate());
}捕获(JAXBEException e){
e、 printStackTrace();
}
}
}
可评估接口{
静态最终可评估真值=真值;
静态最终可评估FALSE=of(FALSE);
布尔求值();
静态可计算的(布尔结果){
返回新的可计算(){
@凌驾
公共布尔求值(){
返回结果;
}
};
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAllow({And.class,Or.class})
抽象类布尔运算符实现可计算{
@xmlanyement(lax=true)
受保护的可评估清单;
@凌驾
公共字符串toString(){
返回getClass().getSimpleName()+“{”+可评估值+“}”;
}
}
@XmlRootElement(name=“And”)
@XmlAccessorType(XmlAccessType.NONE)
类并扩展布尔运算符{
@凌驾
公共布尔求值(){
if(evaluables==null | | evaluables.isEmpty()){
返回true;
}
返回evaluables.stream().reduce(TRUE,(i,j)->Evaluable.of(i.evaluate()&&j.evaluate()).evaluate();
}
}
@XmlRootElement(name=“Or”)
@XmlAccessorType(XmlAccessType.NONE)
类或扩展布尔运算符{
@凌驾
公共布尔求值(){
if(evaluables==null | | evaluables.isEmpty()){
返回true;
}
返回evaluables.stream().reduce(FALSE,(i,j)->Evaluable.of(i.evaluate()| | j.evaluate()).evaluate();
}
}
@XmlRootElement(name=“Condition”)
@XmlAccessorType(XmlAccessType.NONE)
类条件实现了可计算的{
@XmlAttribute(必需=true,name=“value”)
私有布尔结果;
@凌驾
公共布尔求值(){
返回结果;
}
@凌驾
公共字符串toString(){
返回“条件(“+result+”);
}
}

您可以使用B-树(),条件是否为布尔值?@Flown:原则上,是的,条件为布尔值。更精确地说,每个元素都保存用于初始化对象的参数,该对象返回布尔值。