我具有以下XML
结构:
<participants>
<participant side="AWAY">
<team id="18591" name="Orlando Apollos" />
</participant>
<participant side="HOME">
<team id="18594" name="Memphis Express" />
</participant>
</participants>
如果我将FasterXML Jackson
库与JAXB
批注一起使用,如何使用以下方法将参与者字段绑定到两个不同的Participant
对象participantHome
和participantAway
side
和AWAY
的{{1}}属性来绑定字段。
使用以下对象显然不会起作用,因为存在重复的字段:
HOME
如何使用import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "participants")
public class Participants {
@XmlElement(name = "participant")
Participant participantHome;
@XmlElement(name = "participant")
Participant participantAway;
}
批注或自定义JAXB
实现动态绑定那些元素?
答案 0 :(得分:1)
您可以使用“参与者列表”代替两个不同的参与者。 用 @XmlAttribute(name =“ side”,required = true)注释 side 。 然后创建两个不同的参与者对象,并将它们添加到列表中。
答案 1 :(得分:1)
您需要编写自定义反序列化器,因为没有注释可以将列表项绑定到对象中的给定属性。如果您已经使用Jackson
,请尝试实现自定义JsonDeserializer
而不是自定义XmlAdapter
。我们可以通过将内部Participant
对象反序列化为Map
来简化自定义反序列化程序。简单的例子:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
XmlMapper xmlMapper = new XmlMapper();
Participants result = xmlMapper.readValue(xmlFile, Participants.class);
System.out.println(result);
}
}
class ParticipantsXmlAdapter extends JsonDeserializer<Participants> {
@Override
public Participants deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
List<Map<String, Object>> participants = readParticipantsMap(p, ctxt);
Participants result = new Participants();
for (Map<String, Object> participantMap : participants) {
Object side = participantMap.get("side").toString();
if ("AWAY".equals(side)) {
result.setParticipantAway(convert((Map<String, Object>) participantMap.get("team")));
} else if ("HOME".equals(side)) {
result.setParticipantHome(convert((Map<String, Object>) participantMap.get("team")));
}
}
return result;
}
private List<Map<String, Object>> readParticipantsMap(JsonParser p, DeserializationContext ctxt) throws IOException {
MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
JsonDeserializer<Object> mapDeserializer = ctxt.findRootValueDeserializer(mapType);
List<Map<String, Object>> participants = new ArrayList<>();
p.nextToken(); // skip Start of Participants object
while (p.currentToken() == JsonToken.FIELD_NAME) {
p.nextToken(); // skip start of Participant
Object participant = mapDeserializer.deserialize(p, ctxt);
participants.add((Map<String, Object>) participant);
p.nextToken(); // skip end of Participant
}
return participants;
}
private Participant convert(Map<String, Object> map) {
Participant participant = new Participant();
participant.setId(Integer.parseInt(map.get("id").toString()));
participant.setName(map.get("name").toString());
return participant;
}
}
@JsonDeserialize(using = ParticipantsXmlAdapter.class)
class Participants {
private Participant participantHome;
private Participant participantAway;
// getters, setters, toString
}
class Participant {
private int id;
private String name;
// getters, setters, toString
}
打印:
Participants{participantHome=Participant{id=18594, name='Memphis Express'}, participantAway=Participant{id=18591, name='Orlando Apollos'}}
答案 2 :(得分:0)
这里有很多不错的答案和替代方案,但我决定采用结合列表的方法,并通过实现返回正确位置的getter方法来返回正确的home
或away
团队或客队基本上将List
弄平。在处理整个应用程序中的列表时,这将减少计算量。
我向父类(每个home
/ away
参与者)添加了以下代码:
Participant getHome() {
return (Participant) participants.stream()
.filter(p -> p.getSide().equalsIgnoreCase("home"));
}
Participant getAway() {
return (Participant) participants.stream()
.filter(p -> p.getSide().equalsIgnoreCase("away"));
}
感谢您的帮助!