Java JAXB 编组:如何避免在使用 XMLAdapter 编组元素期间添加 XmlElement
Java JAXB Marshalling: How to avoid adding the XmlElement during the marshalling for elements with XMLAdapter
我有一个 JSON 文件,我正在使用 JAXB
将其转换为 XML
。我正在使用 Jackson 读取 JSON
,然后使用 JAXB Marshalling
过程将它们转换为 XML
。 JSON
中的元素可以是随机用户扩展,所以我使用 @JsonAnyGetter
将其存储到 MAP
中,然后我使用适配器将它们转换为 XML 元素。
我只是想知道如何跳过 OuterElement
或父元素的添加,但是我想保留 ÌnnerElementor Child element. Is there a
JAXB` 的处理方式,否则我能做什么实现以下预期结果?
以下是 JSON
文件:
{
"google:g123": {
"google:myField": "myValue"
}
}
以下是我想获得的XML:(预期)
<?xml version="1.0"?>
<extension>
<google:g123>
<google:myField>myValue</google:myField>
</google:g123>
</extension>
以下是我得到的 XML:(当前行为)观察由于 Extension.class
中的变量名而自动添加的 userextension
标记。我想知道如何删除此标签但保留内部元素。
<?xml version="1.0"?>
<extension>
<userextension>
<google:g123>
<google:myField>myValue</google:myField>
</google:g123>
</userextension>
</extension>
以下是我的 Extension
class,JSON
将被反序列化并基于 JAXB
编组创建 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);
}
}
以下是我的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();
}
}
我尝试添加 @XmlAnyElement
但这导致了以下错误:
ExtensionWrapper nor any of its super class is known to this context.
@XmlJavaTypeAdapter(ExtensionsAdapter.class)
@XmlAnyElement
private Map<String, Object> userExtensions;
我只想知道如何在编组期间跳过 userExtension
标记的添加。我只想拥有所有的内部元素。
以下是我的主要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);
}
}
我能够使用 @XmlAnyElement(lax = true)
做到这一点。发布答案,以便将来对寻找类似答案的人有用,而不必浪费时间进行研究。
我创建了一个附加字段:
@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);
}
}
我没有将此元素添加到我的 propOder
。
然后我使用方法填充从userExtension
到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);
}
我有一个 JSON 文件,我正在使用 JAXB
将其转换为 XML
。我正在使用 Jackson 读取 JSON
,然后使用 JAXB Marshalling
过程将它们转换为 XML
。 JSON
中的元素可以是随机用户扩展,所以我使用 @JsonAnyGetter
将其存储到 MAP
中,然后我使用适配器将它们转换为 XML 元素。
我只是想知道如何跳过 OuterElement
或父元素的添加,但是我想保留 ÌnnerElementor Child element. Is there a
JAXB` 的处理方式,否则我能做什么实现以下预期结果?
以下是 JSON
文件:
{
"google:g123": {
"google:myField": "myValue"
}
}
以下是我想获得的XML:(预期)
<?xml version="1.0"?>
<extension>
<google:g123>
<google:myField>myValue</google:myField>
</google:g123>
</extension>
以下是我得到的 XML:(当前行为)观察由于 Extension.class
中的变量名而自动添加的 userextension
标记。我想知道如何删除此标签但保留内部元素。
<?xml version="1.0"?>
<extension>
<userextension>
<google:g123>
<google:myField>myValue</google:myField>
</google:g123>
</userextension>
</extension>
以下是我的 Extension
class,JSON
将被反序列化并基于 JAXB
编组创建 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);
}
}
以下是我的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();
}
}
我尝试添加 @XmlAnyElement
但这导致了以下错误:
ExtensionWrapper nor any of its super class is known to this context.
@XmlJavaTypeAdapter(ExtensionsAdapter.class)
@XmlAnyElement
private Map<String, Object> userExtensions;
我只想知道如何在编组期间跳过 userExtension
标记的添加。我只想拥有所有的内部元素。
以下是我的主要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);
}
}
我能够使用 @XmlAnyElement(lax = true)
做到这一点。发布答案,以便将来对寻找类似答案的人有用,而不必浪费时间进行研究。
我创建了一个附加字段:
@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);
}
}
我没有将此元素添加到我的 propOder
。
然后我使用方法填充从userExtension
到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);
}