使用 jaxb 验证复杂对象中的嵌套对象

Roh*_*hit 3 java jaxb jaxb2 jaxb2-basics

我有一个像 OrderList(有订单列表)这样的对象的 xml 表示,每个订单都有一个商品列表。

我想验证我的商品,如果无效,我想将它们从订单中删除。如果所有商品都无效,那么我会从订单列表中删除该订单。

我已经能够验证订单列表

JAXBContext jaxbContext = JAXBContext.newInstance("com.jaxb");
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File(XSD));
JAXBSource source = new JAXBSource(jaxbContext, orderList);
Validator validator = schema.newValidator();
DataFeedErrorHandler handler = new DataFeedErrorHandler();
validator.setErrorHandler(handler);
validator.validate(source);
Run Code Online (Sandbox Code Playgroud)

我无法找到验证商品的方法。

就像是

for(Order order: orderList){
    for(Commodity commodity: order.getCommodity()){
       if(!isCommodityValid(commodity)){
         // mark for removal
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。

bdo*_*han 5

长话短说

您可以做一个虚拟编组并利用 JAXB 验证机制,而不是javax.xml.validation直接使用这些机制。

利用Marshaller.Listener& ValidationEventHandler(商品验证器)

对于此示例,我们将利用Marshaller.Listener和的各个方面ValidationEventHandler来完成用例。

  • Marshal.Listener- 这将为每个正在编组的对象调用。我们可以使用它来缓存Order我们可能需要Commodity从中删除实例的实例。
  • ValidationEventHandler这将使我们能够访问marshal操作过程中验证时出现的每个问题。对于每个问题,都会传递一个ValidationEvent. 这ValidationEvent将保存一个ValidationEventLocator,从中我们可以获取出现问题的对象。
import javax.xml.bind.*;

public class CommodityValidator extends Marshaller.Listener implements ValidationEventHandler {

    private Order order;

    @Override
    public void beforeMarshal(Object source) {
        if(source instanceof Order) {
            // If we are marshalling an Order Store It
            order = (Order) source;
        }
    }

    @Override
    public boolean handleEvent(ValidationEvent event) {
        if(event.getLocator().getObject() instanceof Commodity) {
            // If the Error was Caused by a Commodity Object Remove it from the Order
            order.setCommodity(null);
            return true;
        }
        return false;
    }

}
Run Code Online (Sandbox Code Playgroud)

演示代码

可以运行以下代码来证明一切正常。

import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.validation.*;
import org.xml.sax.helpers.DefaultHandler;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Orders.class);

        // STEP 1 - Build the Object Model
        Commodity commodity1 = new Commodity();
        commodity1.setId("1");
        Order order1 = new Order();
        order1.setCommodity(commodity1);

        Commodity commodityInvalid = new Commodity();
        commodityInvalid.setId("INVALID");
        Order order2 = new Order();
        order2.setCommodity(commodityInvalid);

        Commodity commodity3 = new Commodity();
        commodity3.setId("3");
        Order order3 = new Order();
        order3.setCommodity(commodity3);

        Orders orders = new Orders();
        orders.getOrderList().add(order1);
        orders.getOrderList().add(order2);
        orders.getOrderList().add(order3);

        // STEP 2 - Check that all the Commodities are Set
        System.out.println("\nCommodities - Before Validation");
        for(Order order : orders.getOrderList()) {
            System.out.println(order.getCommodity());
        }

        // STEP 3 - Create the XML Schema
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(new File("src/forum16953248/schema.xsd"));

        // STEP 4 - Perform Validation with the Marshal Operation
        Marshaller marshaller = jc.createMarshaller();

        // STEP 4a - Set the Schema on the Marshaller
        marshaller.setSchema(schema);

        // STEP 4b - Set the CommodityValidator as the Listener and EventHandler
        CommodityValidator commodityValidator = new CommodityValidator();
        marshaller.setListener(commodityValidator);
        marshaller.setEventHandler(commodityValidator);

        // STEP 4c - Marshal to Anything
        marshaller.marshal(orders, new DefaultHandler());

        // STEP 5 - Check that the Invalid Commodity was Removed
        System.out.println("\nCommodities - After Validation");
        for(Order order : orders.getOrderList()) {
            System.out.println(order.getCommodity());
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

输出

以下是运行演示代码的输出。节点在编组操作后如何删除无效商品。

Commodities - Before Validation
forum16953248.Commodity@3bb505fe
forum16953248.Commodity@699c8551
forum16953248.Commodity@22f4bf02

Commodities - After Validation
forum16953248.Commodity@3bb505fe
null
forum16953248.Commodity@22f4bf02
Run Code Online (Sandbox Code Playgroud)

XML 架构 (schema.xsd)

以下是用于此示例的 XML 架构。

import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.validation.*;
import org.xml.sax.helpers.DefaultHandler;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Orders.class);

        // STEP 1 - Build the Object Model
        Commodity commodity1 = new Commodity();
        commodity1.setId("1");
        Order order1 = new Order();
        order1.setCommodity(commodity1);

        Commodity commodityInvalid = new Commodity();
        commodityInvalid.setId("INVALID");
        Order order2 = new Order();
        order2.setCommodity(commodityInvalid);

        Commodity commodity3 = new Commodity();
        commodity3.setId("3");
        Order order3 = new Order();
        order3.setCommodity(commodity3);

        Orders orders = new Orders();
        orders.getOrderList().add(order1);
        orders.getOrderList().add(order2);
        orders.getOrderList().add(order3);

        // STEP 2 - Check that all the Commodities are Set
        System.out.println("\nCommodities - Before Validation");
        for(Order order : orders.getOrderList()) {
            System.out.println(order.getCommodity());
        }

        // STEP 3 - Create the XML Schema
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(new File("src/forum16953248/schema.xsd"));

        // STEP 4 - Perform Validation with the Marshal Operation
        Marshaller marshaller = jc.createMarshaller();

        // STEP 4a - Set the Schema on the Marshaller
        marshaller.setSchema(schema);

        // STEP 4b - Set the CommodityValidator as the Listener and EventHandler
        CommodityValidator commodityValidator = new CommodityValidator();
        marshaller.setListener(commodityValidator);
        marshaller.setEventHandler(commodityValidator);

        // STEP 4c - Marshal to Anything
        marshaller.marshal(orders, new DefaultHandler());

        // STEP 5 - Check that the Invalid Commodity was Removed
        System.out.println("\nCommodities - After Validation");
        for(Order order : orders.getOrderList()) {
            System.out.println(order.getCommodity());
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Java模型

下面是我用于此示例的对象模型。

命令

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Orders {

    private List<Order> orderList = new ArrayList<Order>();

    @XmlElement(name="order")
    public List<Order> getOrderList() {
        return orderList;
    }

}
Run Code Online (Sandbox Code Playgroud)

命令

public class Order {

    private Commodity commodity;

    public Commodity getCommodity() {
        return commodity;
    }

    public void setCommodity(Commodity commodity) {
        this.commodity = commodity;
    }

}
Run Code Online (Sandbox Code Playgroud)

商品

import javax.xml.bind.annotation.*;

public class Commodity {

    private String id;

    @XmlAttribute
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}
Run Code Online (Sandbox Code Playgroud)