I have the following XML:
<patient>
<name>Mr. Sick</name>
<report>
<paragraph><bold>Conclusion</bold>text...</paragraph>
</report>
</patient>
I would like to convert this to an instance of class Patient like this:
Class Patient {
String name = "Mr. Sick";
String report = "<paragraph><bold>Conclusion</bold>text...</paragraph>";
}
Is it possible to use XStream to convert only part of the XML and keep the report field in XML format? How can it be done?
I solved it by creating an Convertor implementation, as explained here. My solution for the problem is as follows:
Patient.java
public class Patient {
String name;
Report report;
}
Report.java
public class Report {
public String report;
}
An implementation of a Convertor for XStream
public class ReportConverter implements Converter {
@Override
public boolean canConvert(Class classs) {
System.out.println("canConvert: " + classs.getName());
return classs.equals(Report.class);
}
@Override
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
// not used in this example
}
// goes recursive through all the nodes in <report>
String getNodeAsText(HierarchicalStreamReader reader) {
String result;
result = "<" + reader.getNodeName() + ">" + reader.getValue();
while (reader.hasMoreChildren() ) {
reader.moveDown();
result += getNodeAsText(reader);
reader.moveUp();
result += reader.getValue();
}
result += "</" + reader.getNodeName() + ">";
return result;
}
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Report xReport = new Report();
xReport.report = reader.getValue();
while (reader.hasMoreChildren() ) {
reader.moveDown();
xReport.report += getNodeAsText(reader);
reader.moveUp();
xReport.report += reader.getValue();
}
return xReport;
}
}
Example use of the convertor with XStream
XStream xStream = new XStream();
xStream.registerConverter(new ReportConverter());
xStream.alias("patient", Patient.class);
xStream.alias("report", Report.class);
String xml = "<patient><name>Mr. Sick</name><report><paragraph>" +
"some text here<bold>Conclusion</bold>text...</paragraph>" +
"<sdf>hello world</sdf></report></patient>";
Patient patient = (Patient)xStream.fromXML(xml);
System.out.println("patient.name: " + patient.name);
System.out.println("patient.report: " + patient.report.report);
Output
patient: Mr. Sick
patient.report: <paragraph>some text here<bold>Conclusion</bold>text...
...</paragraph><sdf>hello world</sdf>
I don't have the answer for the question asked but I suggest an alternative that could maybe help.
You should probably escaping the content of the report
field. This will help you avoid invalid xml which can be very problematic at unmarshal time.
Here is one simple way to do that (using the commons libray from apache org.apache.commons.lang.StringEscapeUtils):
class Patient {
String name = "Mr. Sick";
String report = StringEscapeUtils.escapeHtml(
"<paragraph><bold>Conclusion</bold>text...</paragraph>");
// report = "<paragraph><bold>Conclusion</bold>text...</paragraph>"
}
Better version of getNodeAsText() that includes the attributes of each node:
private String getNodeAsText(HierarchicalStreamReader reader) {
StringBuilder str = new StringBuilder();
str.append("<")
.append(reader.getNodeName());
for (int i = 0; i < reader.getAttributeCount(); i++) {
String name = reader.getAttributeName(i);
String value = reader.getAttribute(i);
str.append(" ")
.append(name)
.append("=\"")
.append(value)
.append("\"");
}
str.append(">")
.append(reader.getValue());
while (reader.hasMoreChildren()) {
reader.moveDown();
str.append(getNodeAsText(reader));
reader.moveUp();
str.append(reader.getValue());
}
str.append("</")
.append(reader.getNodeName())
.append(">");
return str.toString();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With