2

I have xml something like

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

Instead of creating a message object inside parent object, I need to represent message just as a String . So , when I do parent.message , the output is <type> 15 </type> instead of a message object.

1 Answer 1

4

The idia is to build up the xml of message by processing the HierarchicalStreamReader. If you go down into <messsage> by calling reader.goDown() unfortunately reader.getValue() does not return the whole content of this element.

Model

    @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; }
    }

Converter

    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 + ">");
            }
        }
    }

This test

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

prints out

    <type>15</type>

But it is not every the same content! It ignores for example whitespaces, <foo></foo> would mapped to <foo /> and I don't tested XML entities like &apos; etc.

Maybe it's better to enclose your message in CDATA tags? Like

    <parent>
      <message>
       <![CDATA[
       <type>15</type>
       ]]>
      </message>
    </parent>
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the answer .Actually I have more entities than message mentioned in the question above .. I wanted other entities to behave normally and only the particular node ( in this case message ) to be parsed as a string ) .
In this case I advice you to extend ParentConverter from AnnotationReflectionConverter. You can override unmarshallField(UnmarshallingContext, Object result, Class, Field). If the field name (or field alias) is message, than you use buildRecursiveMessage for any else field you delegate the unmarshaling to super.
sorry, use ReflectionConverter instead of AnnotationReflectionConverter (=deprecated).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.