How to dynamically convert JSON to XML with custom namespace?

Viewed 57

I try to convert a JSON into an XML with the following code

final ObjectMapper objectMapper = new ObjectMapper();
final XmlMapper xmlMapper = new XmlMapper();

JsonNode jsonNode = objectMapper.readTree(jsonString);

String xmlString = xmlMapper
   .writerWithDefaultPrettyPrinter()
   .withRootName("rootname")
   .writeValueAsString(jsonNode);

Basically it works. Does anyone know, how I can add a namespace to the serialized XML-attributes. I've no POJOs for the objects. The convert should generate from this

{
    "Status" : "OK"
}

something like this:

<ns2:rootname xmlns:ns2="http://whatever-it-is.de/">
  <ns2:state>OK</ns2:state>
</ns2:rootname>
2 Answers

just create a pojo and add jackson annotations, e.g.

@JacksonXmlProperty(localName="ns2:http://whatever-it-is.de/")
public class Status {
// ...
}

Or if you want to go without a pojo try a custom serializer which adds namespaces

https://www.baeldung.com/jackson-custom-serialization

You need to provide custom Json Node serialiser and use ToXmlGenerator. See below example:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;

import javax.xml.namespace.QName;
import java.io.IOException;

public class XmlMapperApp {

    public static void main(String... args) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);

        ObjectNode node = xmlMapper.createObjectNode()
                .put("Status", "OK")
                .set("node", xmlMapper.createObjectNode()
                        .put("int", 1)
                        .put("str", "str"));

        SimpleModule module = new SimpleModule();
        module.setSerializerModifier(new BeanSerializerModifier() {
            @Override
            public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
                if (beanDesc.getType().getRawClass().equals(ObjectNode.class)) {
                    return new ObjectNodeJsonSerializer(serializer);
                }
                return super.modifySerializer(config, beanDesc, serializer);
            }
        });
        xmlMapper.registerModule(module);

        System.out.println(xmlMapper.writeValueAsString(node));
    }
}

class ObjectNodeJsonSerializer extends JsonSerializer<JsonNode> {

    private final JsonSerializer baseSerializer;

    ObjectNodeJsonSerializer(JsonSerializer baseSerializer) {
        this.baseSerializer = baseSerializer;
    }

    @Override
    public void serialize(JsonNode value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        ToXmlGenerator xmlGenerator = (ToXmlGenerator) gen;

        xmlGenerator.setNextName(new QName("http://whatever-it-is.de/", "rootname", "anything"));
        baseSerializer.serialize(value, gen, serializers);
    }
}

Above example prints:

<wstxns1:rootname xmlns:wstxns1="http://whatever-it-is.de/">
  <wstxns1:Status>OK</wstxns1:Status>
  <wstxns1:node>
    <wstxns1:int>1</wstxns1:int>
    <wstxns1:str>str</wstxns1:str>
  </wstxns1:node>
</wstxns1:rootname>
Related