В
предыдущем посте я представил
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);
}
}