有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

xml如何递归地比较两个相同但未知类型的Java对象的字段值?

我们正在使用JAXB将XML配置文件解析为Java对象。XML文件是有版本控制的,在将版本1.0和2.0加载到对象中之后,我们希望递归地比较相同但未知类型的两个对象(对于各种事物有许多不同的配置)及其字段值,并打印出差异

对象可能如下所示

@XmlRootElement(name = "HelloWorld")
public class HelloWorldConfiguration {
    private List<HelloWorldObject> helloWorldObjects = new ArrayList<HelloWorldObject>();

    public HelloWorldConfiguration() {
        HelloWorldObject o = new HelloWorldObject();
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
    }

    @XmlElement(name = "helloWorldObject")
    public List<HelloWorldObject> getHelloWorldObjects() {
        return helloWorldObjects;
    }

    public void setHelloWorldObjects(List<HelloWorldObject> helloWorldObjects) {
        this.helloWorldObjects = helloWorldObjects;
    }
}

public class HelloWorldObject {
    private Stage firstName = new Stage("Tony");
    private Stage secondName = new Stage("Stark");
    
    public Stage getFirstName() {
        return firstName;
    }

    public void setFirstName(Stage firstName) {
        this.firstName = firstName;
    }

    public Stage getSecondName() {
        return secondName;
    }

    public void setSecondName(Stage secondName) {
        this.secondName = secondName;
    }

}

例如,我们希望了解有关上述HelloWorldConfiguration对象的以下更改

  • 列表中还有其他“HelloWorldObject”项(必须在屏幕上打印带有属性的项)
  • 位置n处的“HelloWorldObject”有一个新的“firstName”值(已更改的字段或XML元素的名称及其值应打印出来)
  • 新的“HelloWorldObject”列表缩短了以下两个元素(缺少的元素必须与所有属性和值一起打印)

我的问题如下

  • 您是在Java对象级别上通过反射来解决这个问题,还是比较这两个不同的XML文件
  • 有没有图书馆已经为我做了类似的事情?在XML还是Java对象级别
  • 有什么例子吗

共 (1) 个答案

  1. # 1 楼答案

    免责声明我是JAXB2 Basics插件包的作者,其中包括JAXB2 Equals plugin


    如果您从XML模式生成类,那么JAXB2 Equals plugin在本用例中可能对您有用

    JAXB2 Equals plugin能够生成equals方法,对JAXB类实例进行深层结构遍历值比较:

    public boolean equals(Object object) {
        final EqualsStrategy strategy = JAXBEqualsStrategy.INSTANCE;
        return equals(null, null, object, strategy);
    }
    
    public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
        if (!(object instanceof PurchaseOrderType)) {
            return false;
        }
        if (this == object) {
            return true;
        }
        final PurchaseOrderType that = ((PurchaseOrderType) object);
        {
            USAddress lhsShipTo;
            lhsShipTo = this.getShipTo();
            USAddress rhsShipTo;
            rhsShipTo = that.getShipTo();
            if (!strategy.equals(LocatorUtils.property(thisLocator, "shipTo", lhsShipTo), LocatorUtils.property(thatLocator, "shipTo", rhsShipTo), lhsShipTo, rhsShipTo)) {
                return false;
            }
        }
        {
            USAddress lhsBillTo;
            lhsBillTo = this.getBillTo();
            USAddress rhsBillTo;
            rhsBillTo = that.getBillTo();
            if (!strategy.equals(LocatorUtils.property(thisLocator, "billTo", lhsBillTo), LocatorUtils.property(thatLocator, "billTo", rhsBillTo), lhsBillTo, rhsBillTo)) {
                return false;
            }
        }
        // ...
        return true;
    }
    

    我希望你有这个想法。你可以提供一个“定位器”,它可以追踪被比较的事物的位置,还可以提供一个策略来比较各个价值观

    因此,您可以:

    • 深入比较模式派生的JAXB类实例
    • 知道什么是不同的(精确值)
    • 知道其中是差异(在对象结构中的确切位置)

    整个过程没有反射,因此速度很快

    下面是another project的一个片段。这是我在其中一个测试中比较对象“之前”和“之后”,并记录差异

        final EqualsStrategy strategy = new org.jvnet.hyperjaxb3.lang.builder.ExtendedJAXBEqualsStrategy() {
    
            @Override
            public boolean equals(ObjectLocator leftLocator,
                    ObjectLocator rightLocator, Object lhs, Object rhs) {
                if (!super.equals(leftLocator, rightLocator, lhs, rhs)) {
                    logger.debug("Objects are not equal.");
                    super.equals(leftLocator, rightLocator, lhs, rhs);
                    logger.debug("Left: "
                            + (lhs == null ? "null" : lhs.toString()));
                    if (leftLocator != null) {
                        logger.debug("At [" + leftLocator.getPathAsString()
                                + "].");
                    }
                    logger.debug("Right: "
                            + (rhs == null ? "null" : rhs.toString()));
                    if (rightLocator != null) {
                        logger.debug("At [" + rightLocator.getPathAsString()
                                + "].");
                    }
                    return false;
                } else
    
                {
                    return true;
                }
            }
    
        };
    

    从另一方面来说,这种方法并不像你从风投那里知道的那样是一种真正的“差别”。它只表示某些内容不同,但不计算任何“最短编辑距离”