I have a JSON file that I am converting to XML
using the JAXB
. I am reading the JSON
using the Jackson then I am converting them to XML
using the JAXB Marshalling
process. The elements in JSON
can be random user extension so I am using the @JsonAnyGetter
to store it into MAP
then I am using the adapter to convert them to XML elements.
I just wanted to know how can I skip the addition of the OuterElement
or Parent element however I would like to retain the ÌnnerElement or Child element. Is there a
or Child element. Is there a
JAXB` way of doing it or else what can I do to achieve the following desired result?
Following is the JSON
file:
{
"google:g123": {
"google:myField": "myValue"
}
}
Following is the XML that I would like to obtain: (Expected)
<?xml version="1.0"?>
<extension>
<google:g123>
<google:myField>myValue</google:myField>
</google:g123>
</extension>
Following is the XML that I am getting: (Current Behaviour) Observe the userextension
tag which is being added automatically due to the variable name from the Extension.class
. I would like to know how can I remove this tag but retain the inner elements.
<?xml version="1.0"?>
<extension>
<userextension>
<google:g123>
<google:myField>myValue</google:myField>
</google:g123>
</userextension>
</extension>
Following is my Extension
class to which JSON
will be deserialized and based on which JAXB
will marshal to create XML:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "extension")
public class Extension {
@XmlJavaTypeAdapter(ExtensionsAdapter.class)
private Map < String, Object > userExtensions;
@JsonAnyGetter
public Map < String, Object > getUserExtensions() {
return userExtensions;
}
@JsonAnySetter
public void setUserExtensions(String key, Object value) {
if (userExtensions == null) {
userExtensions = new HashMap < String, Object > ();
}
userExtensions.put(key, value);
}
}
Following is my ExtensionAdapter.class
:
public class ExtensionsAdapter extends XmlAdapter<ExtensionWrapper, Map<String, Object>> {
private DocumentBuilder documentBuilder;
public ExtensionsAdapter() throws Exception {
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
public static class ExtensionWrapper {
@XmlAnyElement
List elements;
}
@SuppressWarnings("unchecked")
@Override
public ExtensionWrapper marshal(Map<String, Object> extensions) throws Exception {
if (extensions == null) {
return null;
}
ExtensionWrapper wrapper = new ExtensionWrapper();
List elements = new ArrayList();
for (Map.Entry<String, Object> extension : extensions.entrySet()) {
if (extension.getValue() instanceof Map) {
elements.add(new JAXBElement<ExtensionWrapper>(new QName(getCleanLabel(extension.getKey())), ExtensionWrapper.class, marshal((Map) extension.getValue())));
} else {
elements.add(new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString()));
}
}
wrapper.elements = elements;
return wrapper;
}
// Return a XML-safe attribute. Might want to add camel case support
private String getCleanLabel(String attributeLabel) {
attributeLabel = attributeLabel.replaceAll("[()]", "").replaceAll("[^\\w\\s]", "_").replaceAll(" ", "_");
return attributeLabel;
}
@Override
public Map<String, Object> unmarshal(ExtensionWrapper valurType) throws Exception {
throw new NotImplementedException();
}
}
I tried adding the @XmlAnyElement
but thats resulting in the following error: ExtensionWrapper nor any of its super class is known to this context.
@XmlJavaTypeAdapter(ExtensionsAdapter.class)
@XmlAnyElement
private Map<String, Object> userExtensions;
I just want to know how can I skip the addition of the userExtension
tag during the marshalling. I just want to have all the inner elements.
Following is my main class:
public class Main
{
public static void main(String[] args) {
//jsonStream is the input json which I am reading from a file
final JsonParser jsonParser = jsonFactory.createParser(jsonStream);
jsonParser.setCodec(new ObjectMapper());
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final JsonNode jsonNode = jsonParser.readValueAsTree();
final Extension eventInfo = objectMapper.treeToValue(jsonNode, Extension.class);
JAXBContext context = JAXBContext.newInstance(Extension.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.marshal(((XmlSupportExtension) eventInfo).xmlSupport(), System.out);
}
}
I was able to do it using the @XmlAnyElement(lax = true)
. Posting the answer so it can be useful to somebody in the future who is looking for a similar answer and does not have to waste time trying to research.
I created an additional field:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "extension")
public class Extension {
//Old field used only for getting value from JSON
private Map < String, Object > userExtensions;
//New Field which will be added to my XML
@XmlElement(lax=true)
private Object[] xmlExtensions;
@JsonAnyGetter
public Map < String, Object > getUserExtensions() {
return userExtensions;
}
@JsonAnySetter
public void setUserExtensions(String key, Object value) {
if (userExtensions == null) {
userExtensions = new HashMap < String, Object > ();
}
userExtensions.put(key, value);
}
}
I did not add this element to my propOder
.
Then I used the a method to populate the fields from userExtension
to XmlExtension
:
private Object[] extensionBuilder(Map<String, Object> extensions) {
if (extensions == null) {
return null;
}
return extensions.entrySet().stream().map(extension -> {
if (extension.getValue() instanceof Map) {
// return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class,
// (JAXBElement) extensionBuilder((Map) extension.getValue())[0]);
final Object[] result = extensionBuilder((Map) extension.getValue());
return Arrays.stream(result)
.map(innerExtension -> new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class,
(JAXBElement) innerExtension))
.collect(Collectors.toList());
} else {
return Arrays
.asList(new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString()));
}
}).flatMap(List::stream).toArray(Object[]::new);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.