问题
I have a xml representation of object like OrderList (has list of) Orders and each order has a list of commodities.
I want to validate my commodities and if not valid I want to remove them from order. If all commodities are invalid then I remove the order from the orderlist.
I have been able to validate Orderlist
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);
I am not able to find a way to validate commodities.
Something like
for(Order order: orderList){
for(Commodity commodity: order.getCommodity()){
if(!isCommodityValid(commodity)){
// mark for removal
}
}
}
Any help would be greatly appreciated.
回答1:
TL;DR
You can do a dummy marshal and leverage the JAXB validation mechanisms rather than using the javax.xml.validation
mechanisms directly.
LEVERAGING Marshaller.Listener
& ValidationEventHandler
(CommodityValidator)
For this example we will leverage aspects of Marshaller.Listener
and ValidationEventHandler
to accomplish the use case.
Marshal.Listener
- This will be called for each object being marshalled. We can use it to cache the instance ofOrder
that we may need to remove the instance ofCommodity
from.ValidationEventHandler
this will give us access to each problem occuring with validation during themarshal
operation. For each problem it will be passed aValidationEvent
. ThisValidationEvent
will hold aValidationEventLocator
from which we can get the object that had the problem being marshalled.
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;
}
}
DEMO CODE
The following code can be run to prove that everything works.
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());
}
}
}
OUTPUT
Below is the output from running the demo code. Node how after the marshal operation the invalid commodity was removed.
Commodities - Before Validation
forum16953248.Commodity@3bb505fe
forum16953248.Commodity@699c8551
forum16953248.Commodity@22f4bf02
Commodities - After Validation
forum16953248.Commodity@3bb505fe
null
forum16953248.Commodity@22f4bf02
XML SCHEMA (schema.xsd)
Below is the XML schema used for this example.
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="orders">
<complexType>
<sequence>
<element name="order" minOccurs="0" maxOccurs="unbounded">
<complexType>
<sequence>
<element name="commodity">
<complexType>
<attribute name="id" type="int"/>
</complexType>
</element>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
JAVA MODEL
Below is the object model I used for this example.
Orders
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;
}
}
Order
public class Order {
private Commodity commodity;
public Commodity getCommodity() {
return commodity;
}
public void setCommodity(Commodity commodity) {
this.commodity = commodity;
}
}
Commodity
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;
}
}
来源:https://stackoverflow.com/questions/16953248/validate-nested-object-from-complex-object-using-jaxb