I have a very big and complex xml and i want to load only selected fields into my object. I have tried with xstream but what i understood is my xml structure must be similar to my pojo. I am providing sample i/p and o/p for better understanding
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Pojo will be
class Note{
long noteId;
String body;
//getters and setters
}
Question is how to skip xml elements while loading it into pojo?
You can do it with Jackson XML librairy. Jackson is maybe more famous for JSON
serialising/deserialising but it has a XML extension.
If your XML file is big, look at the above link to see how you can partially/incrementally read it in order to get the best performances.
Anyway following is an example on how to read only a subset of properties using the @JsonIgnore
annotation on the fields you don't want deserialised:
@JacksonXmlRootElement(localName = "jokes")
class Jokes {
@JacksonXmlProperty(localName = "joke")
@JacksonXmlElementWrapper(useWrapping = false)
private Joke[] jokes;
// getter, setter omitted
}
class Joke {
@JacksonXmlProperty(isAttribute = true)
long id;
@JacksonXmlProperty(localName = "title")
String title;
@JsonIgnore
String author;
@JacksonXmlProperty(localName = "like")
long like;
@JsonIgnore
String content;
public String toString() {
return Arrays.stream(new Object[] {id, title, author, like, content})
.map(o -> o!=null ? o.toString() : "EMPTY")
.collect(Collectors.joining(", ", "[", "]"));
}
// getters, setters omitted
}
With a sample file:
<jokes>
<joke id="123">
<title>C'est l'histoire d'un mec</title>
<author>Coluche</author>
<content>Blah blah blah</content>
<like>4509</like>
</joke>
<joke id="777">
<title>Si j'ai bien tout lu freud</title>
<author>Coluche</author>
<content>Blah blah blah</content>
<like>345</like>
</joke>
</jokes>
And the main()
public class XmlJokeReader {
public static void main(String[] args) throws JsonProcessingException, IOException {
XmlMapper mapper = new XmlMapper();
Jokes jokesDoc = mapper.readValue(new File("./data/jokes.xml"), Jokes.class);
Arrays.stream(jokesDoc.getJokes()).forEach(j -> System.out.println(j.toString()));
}
}
The output is (note the EMPTY fields):
[123, C'est l'histoire d'un mec, EMPTY, 4509, EMPTY]
[777, Si j'ai bien tout lu freud, EMPTY, 345, EMPTY]
You can also create a pojo that contains only the fields you need - then not using @JsonIgnore
. For that the XmlMapper
has to be informed to ignore unknown XML properties.
XmlMapper mapper = new XmlMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
The full example for the case where you want a pojo with only a few fields:
Let say we have a pojo with only id
and title
:
class Joke {
@JacksonXmlProperty(isAttribute = true)
long id;
@JacksonXmlProperty(localName = "title")
String title;
public String toString() {
return new StringBuffer().append('[')
.append(id).append(',')
.append(title).append(']').toString();
}
// getters setters
}
Executing the following main()
with the xml file described above:
public class XmlJokeReader {
public static void main(String[] args) throws JsonProcessingException, IOException {
XmlMapper mapper = new XmlMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Jokes jokesDoc = mapper.readValue(new File("./data/jokes.xml"), Jokes.class);
for (Joke joke : jokesDoc.getJokes()) {
System.out.println(joke.toString());
}
}
}
Will give:
[123,C'est l'histoire d'un mec]
[777,Si j'ai bien tout lu freud]