получить xml как строку вместо класса с помощью xstream

У меня есть xml что-то вроде

<parent>
  <message>
   <type>15</type>
  </message>
</parent>

Вместо того, чтобы создавать объект сообщения внутри родительского объекта, мне нужно представить сообщение как строку. Итак, когда я делаю parent.message, вывод <type> 15 </type> вместо объекта сообщения.


person Prabesh Shrestha    schedule 15.05.2014    source источник


Ответы (1)


Идея состоит в том, чтобы создать xml сообщения, обработав файл HierarchicalStreamReader. Если вы спуститесь в <messsage>, вызвав reader.goDown(), к сожалению, reader.getValue() не вернет все содержимое этого элемента.

Модель

    @XStreamAlias("parent")
    @XStreamConverter(value = ParentConverter.class)
    public class Parent {
        private final String message;

        public Parent(final String message) { this.message = message; }
        public String getMessage() { return message; }
    }

Конвертер

    public class ParentConverter implements Converter {
        @Override
        public boolean canConvert(@SuppressWarnings("rawtypes") final Class type) {
            return Parent.class.isAssignableFrom(type);
        }

        @Override
        public void marshal(Object source, HierarchicalStreamWriter writer,
                MarshallingContext context) {
            throw new UnsupportedOperationException("unmarshaling only");
        }

        @Override
        public Object unmarshal(HierarchicalStreamReader reader,
                UnmarshallingContext context) {

            reader.moveDown();
            if (!"message".equals(reader.getNodeName())) {
                throw new ConversionException("Expected message, but was "
                        + reader.getNodeName());
            }
            final StringBuilder message = new StringBuilder();
            while (reader.hasMoreChildren()) {
                reader.moveDown();
                buildRecursiveMessage(reader, message);
                reader.moveUp();
            }
            reader.moveUp();

            final Parent parent = new Parent(message.toString());
            return parent;
        }

        private void buildRecursiveMessage(final HierarchicalStreamReader reader,
                final StringBuilder sb) {
            // Build start-tag
            final String nodeName = reader.getNodeName();
            sb.append("<" + nodeName);

            // Build attributes
            final int numAttributes = reader.getAttributeCount();
            if (numAttributes > 0) {
                sb.append(" ");
                for (int i = 0; i < numAttributes; i++) {
                    final String attributeName = reader.getAttributeName(i);
                    final String attributeValue = reader.getAttribute(i);
                    sb.append(attributeName + "=\"" + attributeValue + "\"");

                    final boolean lastAttribute = (i == numAttributes - 1);
                    if (!lastAttribute) {
                        sb.append(", ");
                    }
                }
            }

            // Build children
            final boolean containsChildren = reader.hasMoreChildren();
            final boolean containsValue = !reader.getValue().isEmpty();
            final boolean empty = !containsChildren && !containsValue;

            sb.append(!empty ? ">" : " />");

            if (containsChildren) {
                while (reader.hasMoreChildren()) {
                    reader.moveDown();
                    buildRecursiveMessage(reader, sb);
                    reader.moveUp();
                }
            } else if (containsValue) {
                sb.append(reader.getValue());
            }

            // Build end-tag
            if (!empty) {
                sb.append("</" + nodeName + ">");
            }
        }
    }

Этот тест

    public static void main(String[] args) {
        final XStream xstream = new XStream();
        xstream.processAnnotations(Parent.class);

        // Deserialize
        final String xml = "<parent><message><type>15</type></message></parent>";
        final Parent parent = (Parent) xstream.fromXML(xml);
        System.out.println(parent.getMessage());
    }

распечатывает

    <type>15</type>

Но это не каждый тот же самый контент! Он игнорирует, например, пробелы, <foo></foo> будет отображаться в <foo />, и я не тестировал объекты XML, такие как &apos; и т. д.

Может быть, лучше заключить ваше сообщение в теги CDATA? Нравиться

    <parent>
      <message>
       <![CDATA[
       <type>15</type>
       ]]>
      </message>
    </parent>
person Vertex    schedule 17.05.2014
comment
Спасибо за ответ. На самом деле у меня больше сущностей, чем сообщения, упомянутые в вопросе выше. Я хотел, чтобы другие сущности вели себя нормально, и только конкретный узел (в данном случае сообщение) анализировался как строка). - person Prabesh Shrestha; 17.05.2014
comment
В этом случае я советую вам расширить ParentConverter из AnnotationReflectionConverter. Вы можете переопределить unmarshallField(UnmarshallingContext, Object result, Class, Field). Если имя поля (или псевдоним поля) message, то вы используете buildRecursiveMessage для любого другого поля, делегируя демаршалинг super. - person Vertex; 20.05.2014
comment
извините, используйте ReflectionConverter вместо AnnotationReflectionConverter (=устарело). - person Vertex; 20.05.2014