РЕДАКТИРОВАТЬ:
Я перепутал некоторое время и пришел к следующему результату XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<List>
<client name="Robert">
<fileNames name="anleitung.pdf"/>
<fileNames name="fernseher.jpg"/>
<fileNames name="pikantesfoto.jpg"/>
</client>
<client name="Jakob">
<fileNames name="fernseher.jpg"/>
<fileNames name="pikantesfoto.jpg"/>
<fileNames name="tagebuch.txt"/>
</client>
</List>
Это не очень много отношений, но это близко, мне нужно удалить избыточность данных.
"Имена файлов" должны быть отдельными элементами, которые и клиенты должны указывать на них. Поэтому, если есть один файл с тем же именем файла с других клиентов, он должен появляться только один раз.
Это мои классы:
Маршаллер: открытый класс XMLMarshaller {
private Pool pool;
public XMLMarshaller(Pool pool) {
this.pool = pool;
}
public void marshal() {
JAXBContext jc;
try {
jc = JAXBContext.newInstance(Pool.class, Client.class, FileName.class);
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save XML-File");
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("XML-Document", "*.xml"));
File path = fileChooser.showSaveDialog(new Stage());
if (path.toString().endsWith(".xml") == false) {
path = new File(path.toString() + ".xml");
}
if (path.isFile() == false)
path.createNewFile();
FileOutputStream fos = new FileOutputStream(path);
OutputStreamWriter xmlOut = new OutputStreamWriter(fos, Charset.forName("UTF8"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
QName qName = new QName("List");
JAXBElement<Pool> jaxbElement = new JAXBElement<>(qName, Pool.class, pool);
marshaller.marshal(jaxbElement, xmlOut);
xmlOut.flush();
xmlOut.close();
} catch (Exception e) {e.printStackTrace();}
}
}
Пул (содержит список всех существующих "имен файлов" и "Клиенты"):
public class Pool {
private List<FileName> fileNames_pool;
private List<Client> clients;
public Pool() {
this.fileNames_pool = new ArrayList<>(20);
this.clients = new ArrayList<>(20);
}
public List<FileName> getFileNameList() {
return this.fileNames_pool;
}
public List<FileName> getFileNames_pool() {
return this.fileNames_pool;
}
@XmlAnyElement(lax = true)
public List<Client> getClientList() {
return this.clients;
}
public boolean addClient(String clientName) {
this.clients.add(new Client(clientName));
return true;
}
public boolean addFileName(int clientIndex, String fileName) {
int foundIndex = 0;
boolean foundOne = false;
for (int i=0; i<fileNames_pool.size(); ++i) {
if (fileNames_pool.get(i).name == fileName) {
foundIndex = i;
foundOne = true;
break;
}
}
if (foundOne) {
clients.get(clientIndex).addFileName(fileNames_pool.get(foundIndex));
} else {
FileName temp = new FileName(fileName);
fileNames_pool.add(temp);
clients.get(clientIndex).addFileName(temp);
}
return true;
}
}
Клиент (там будет несколько экземпляров/объектов): @XmlRootElement public class Client {
static int numberOfClients = 0;
private int id;
@XmlAttribute
public String name;
public List<FileName> fileNames = new ArrayList<>();
public Client() {
}
public Client(String name) {
this.name = name;
this.id = numberOfClients++;
}
@XmlElement
public List<FileName> getFileNames() {
return this.fileNames;
}
public void addFileName(FileName fileName) {
this.fileNames.add(fileName);
}
}
FileNames (там также будут несколько экземпляров):
//@XmlRootElement
public class FileName {
// public static int instanceCounter = 0;
//
// @XmlIDREF
// public int idref = 0;
@XmlAttribute
public String name;
public FileName() {
}
public FileName(String name) {
this.name = name;
// idref = instanceCounter++;
}
}
Вы увидите, что я иногда действительно перепутал вещи, но у меня совершенно нет идей о том, что может сработать, а что нет. Класс пула - это что-то вроде обертки, как сказал мне Блейз Дохан, если я не ошибаюсь. И что я полностью не понял: почему должен быть "id", основанный на классе строк?
Требования JAXB
Каждый объект должен быть ссылкой через отношения сдерживания/вложения, такие как @XmlElement
, @XmlElementRef
или @XmlAnyElement(lax=true)
.
Неконтаминационные отношения
Если у вас есть дерево, как формируется выше требования JAXB вы можете формировать отношения внутри документа с использованием @XmlID
/@XmlIDREF
(см http://blog.bdoughan.com/2010/10/jaxb-and-shared-references- xmlid-and.html). Вот где следующее выражение, сделанное вами в вашем вопросе, происходит от:
По моему мнению, это должно сработать, если я просто сохраню 2 списка в обоих классах, которые указывают друг на друга, но я прочитал в Интернете, что нужно задействовать 3-й класс для сопоставления этих 2-х классов во многих отношениях.
Что ты можешь сделать?
Взгляните на этот ответ, который я дал другому вопросу. В этом ответе я продемонстрирую, как вы можете использовать XmlAdapter
для представления первого вхождения объекта через сдерживание и последующие ссылки через ссылку.
Вот пример того, как сопоставить POJO с XML с помощью jaxb http://www.mkyong.com/java/jaxb-hello-world-example/
Однако в вашем случае у вас двунаправленные отношения, ваш класс ClientName
имеет ссылку на класс FileName
, а в FileName
возвращается ссылка на ClientName
. В случае двунаправленного XML-сопоставления с использованием JAXB вы захотите использовать тег @XmlTransient
для одного из отношений. @XmlTransient
может не быть тем, что вы ищете, потому что для любого поля аннотируется, оно будет удалено с этого направления. Существует решение этого с использованием метода afterUnmarshal
. http://www.tutorialspoint.com/java/xml/javax_xml_bind_unmarshaller.listener_afterunmarshal.htm
Или вы можете использовать MOXy @XmlInverseReference
для обработки unmarshalling для вас https://www.eclipse.org/eclipselink/documentation/2.4/moxy/shared_reference_relationships005.htm