В
предыдущем посте я представил
EclipseLink JAXB (Moxy) «сек
@XmlVariableNode расширение. В этом посте я продемонстрирую, как
можно использовать @XmlVariableNode для решения
интересного вопроса, с которым я столкнулся при переполнении стека . В этом вопросе вместо коллекции, представленной с элементом, который появлялся несколько раз, имя элемента содержало индекс. Хотя я бы никогда не рекомендовал структурировать ваш XML-документ таким образом, иногда вы сталкиваетесь с ним и должны иметь возможность отобразить его.
XML Ввод (input.xml) / Вывод
Ниже показано, как выглядит проблемный XML. В этом примере количество различных элементов с префиксом
номера телефона неизвестно.
<?xml version="1.0" encoding="UTF-8"?> <customer> <phone-number1 type="work">555-1111</phone-number1> <phone-number2 type="home">555-2222</phone-number2> <phone-number3 type="cell">555-3333</phone-number3> </customer>
Модель Java
Ниже приведена модель Java, которую мы будем использовать в этом примере.
В конечном итоге мы хотим представить XML в Java как Customer , у которого есть коллекция экземпляров PhoneNumber . Для этого варианта использования мы будем использовать расширение @XmlVariableNode от MOXy . Указанный объект не имеет свойства, которое мы можем использовать для хранения имени узла, поэтому мы будем использовать XmlAdapter для преобразования PhoneNumber в объект, который имеет.
package blog.variablenode.enumeratedlist; import java.util.*; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.eclipse.persistence.oxm.annotations.XmlVariableNode; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlVariableNode("nodeName") @XmlJavaTypeAdapter(PhoneNumberAdapter.class) private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); }
Обратите внимание, что PhoneNumber не имеет поля для хранения имени узла
package blog.variablenode.enumeratedlist; import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class PhoneNumber { @XmlAttribute private String type; @XmlValue private String number; }
Мы будем использовать XmlAdapter для преобразования PhoneNumber в AdaptedPhoneNumber . AdaptedPhoneNumber имеет поле nodeName (строка 14), на которое мы ссылались в аннотации @XmlVariableNode, которую мы использовали в поле phoneNumbers в классе Customer . Мы аннотируем это поле с помощью @XmlTransient, чтобы предотвратить его маршалинг / демаршаллинг (см. JAXB и Unmapped Properties ). Мы будем использовать расширение @XmlPath MOXy, чтобы избежать необходимости копировать содержимое PhoneNumber в AdaptedPhoneNumber (см .: XPath Based Mapping ).
package blog.variablenode.enumeratedlist; import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.adapters.XmlAdapter; import org.eclipse.persistence.oxm.annotations.XmlPath; public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{ private int counter = 1; public static class AdaptedPhoneNumber { @XmlTransient public String nodeName; @XmlPath(".") public PhoneNumber phoneNumber; } @Override public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception { AdaptedPhoneNumber adaptedPhoneNumber = new AdaptedPhoneNumber(); adaptedPhoneNumber.nodeName = "phone-number" + counter++; adaptedPhoneNumber.phoneNumber = phoneNumber; return adaptedPhoneNumber; } @Override public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception { return adaptedPhoneNumber.phoneNumber; } }
Следующий демонстрационный код может быть использован, чтобы доказать, что все работает. Поскольку PhoneNumberAdapter является состоящим из состояния, нам нужно установить его экземпляр на маршаллере (строка 17) .
package blog.variablenode.enumeratedlist; import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/blog/variablenode/enumeratedlist/input.xml"); Customer customer = (Customer) unmarshaller.unmarshal(xml); Marshaller marshaller = jc.createMarshaller(); PhoneNumberAdapter phoneNumberAdapter = new PhoneNumberAdapter(); marshaller.setAdapter(phoneNumberAdapter); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(customer, System.out); } }