XStream: сохраняйте части XML как XML

У меня есть следующий XML:

<patient>
    <name>Mr. Sick</name>
    <report>
        <paragraph><bold>Conclusion</bold>text...</paragraph>
    </report>
</patient>

Я хотел бы преобразовать это в экземпляр класса Patient следующим образом:

Class Patient {
    String name = "Mr. Sick";
    String report = "<paragraph><bold>Conclusion</bold>text...</paragraph>";
}

Можно ли использовать XStream для преобразования только части XML и сохранения поля отчета в формате XML? Как это сделать?


person boes    schedule 31.08.2011    source источник
comment
Вы можете сделать это, используя реализацию JAXB (Metro, EclipseLink MOXy, Apache JaxMe) с аннотацией @XmlAnyElement: blog.bdoughan.com/2011/04/   -  person bdoughan    schedule 31.08.2011
comment
Спасибо. Хотя я не использовал это решение, оно помогло найти ответ. Поиск по @XmlAnyElement в сочетании с XStream дал мне достаточно информации, чтобы снова начать работу. Я опубликовал свой ответ на этот вопрос.   -  person boes    schedule 31.08.2011


Ответы (3)


Я решил это, создав реализацию Convertor, как описано здесь. Мое решение проблемы следующее:

Пациент.java

public class Patient {
    String name;
    Report report;
}

Отчет.java

public class Report {
    public String report;
}

Реализация преобразователя для 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; 
    } 
}

Пример использования преобразователя с 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);

Вывод

patient: Mr. Sick
patient.report: <paragraph>some text here<bold>Conclusion</bold>text...
    ...</paragraph><sdf>hello world</sdf>
person boes    schedule 31.08.2011

У меня нет ответа на заданный вопрос, но я предлагаю альтернативу, которая может помочь.

Вероятно, вам следует экранировать содержимое поля report. Это поможет вам избежать неверных XML-файлов, которые могут быть очень проблематичными во время немаршалирования.

Вот один простой способ сделать это (используя общедоступную библиотеку от apache org.apache.commons.lang.StringEscapeUtils):

class Patient {
   String name = "Mr. Sick";
   String report = StringEscapeUtils.escapeHtml(
         "<paragraph><bold>Conclusion</bold>text...</paragraph>");

  // report = "&lt;paragraph&gt;&lt;bold&gt;Conclusion&lt;/bold&gt;text...&lt;/paragraph&gt;"
}
person aymeric    schedule 31.08.2011
comment
Это сработает, если я начну с экземпляра класса Patient, а затем создам XML. Мне нужно наоборот. У меня есть база данных, заполненная проблемными XML-сообщениями. Мне нравится преобразовывать их в класс Java, как показано в моем примере. - person boes; 31.08.2011
comment
Хотите показать нам, что у вас есть для кода в этой конкретной ситуации? - person Wivani; 31.08.2011

Улучшенная версия getNodeAsText(), которая включает атрибуты каждого узла:

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();

}

person Leo Gomes    schedule 23.02.2012