[英]JAXB removing unnecessary nested XML tag
Currently I have following output from my program: 目前,我的程序有以下输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container>
<elements>
<property name="e1">
<foo name="Alex" status="Married"/>
</property>
<property name="e2">
<foo name="Chris" status="Married with 2 children"/>
</property>
</elements>
</container>
As you can see, having both <container>
and <elements>
tags is useless. 如您所见,同时具有<container>
和<elements>
标签是没有用的。 I'd like to remove <elements>
, so the output would look like: 我想删除<elements>
,因此输出如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container>
<property name="e1">
<foo name="Alex" status="Married"/>
</property>
<property name="e2">
<foo name="Chris" status="Married with 2 children"/>
</property>
</container>
Code that's generating first output is listed below: 下面列出了生成第一个输出的代码:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Container {
@XmlElement
@XmlJavaTypeAdapter(MyAdapter.class)
private Map<String, Foo> elements = new HashMap<String, Foo>();
public Container() {
this.elements = new HashMap<String, Foo>();
}
public Map<String, Foo> getElements() {
return elements;
}
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
@XmlRootElement(name = "foo")
static class Foo {
@XmlAttribute
public String name;
@XmlAttribute
public String status;
public Foo(String name, String status) {
this.name = name;
this.status = status;
}
public Foo() {
}
}
public static void main(String[] args) throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(Container.class);
final Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
final Container c = new Container();
final Map<String, Foo> elementsMap = c.getElements();
elementsMap.put("e1", new Foo("Alex", "Married"));
elementsMap.put("e2", new Foo("Chris", "Married with 2 children"));
m.marshal(c, System.out);
}
}
And MyAdapter
class, based on JAXB @XmlAdapter: Map -> List adapter? 和MyAdapter
类,基于JAXB @XmlAdapter:Map-> List adapter? (marshall only) : (仅限马歇尔) :
public class MyAdapter extends XmlAdapter<MyAdapter.AdaptedFoo, Map<String, Foo>> {
static class AdaptedFoo {
public List<Property> property = new ArrayList<>();
}
public static class Property {
@XmlAttribute
public String name;
@XmlElementRef(type = Foo.class)
public Foo value;
}
@Override
public Map<String, Foo> unmarshal(AdaptedFoo v) throws Exception {
return null;
}
@Override
public AdaptedFoo marshal(Map<String, Foo> map) throws Exception {
if (null == map) {
return null;
}
AdaptedFoo adaptedFoo = new AdaptedFoo();
for (Entry<String, Foo> entry : map.entrySet()) {
Property property = new Property();
property.name = entry.getKey();
property.value = entry.getValue();
adaptedFoo.property.add(property);
}
return adaptedFoo;
}
}
How can I remove <elements>
tag from my output? 如何从输出中删除<elements>
标签?
edit: I've found 'dirty' way to do it - setting @XmlRootElement(name = "")
for Container
class . 编辑: 我发现这样做的“肮脏”方法-为Container
类设置@XmlRootElement(name = "")
。 But is there any 'elegant' way? 但是,有什么“优雅”的方式吗?
The XML element <elements>
is required to associate the enclosed element seqence with the property Map<?,?> elements
. 需要XML元素<elements>
来将封闭的元素序列与属性Map<?,?> elements
关联。 You can't drop it: how would an unmarshaller know where the <property>
elements belong *on the level of the element <container>
. 您不能删除它:解组员如何知道<property>
元素在*元素<container>
级别上的位置。
Having a List<Property>
is different since JAXB handles repeated elements x "hardwired" as a List<?> x
, so there's no need for a wrapper. 具有List<Property>
有所不同,因为JAXB将“硬连线”的重复元素x作为List<?> x
,因此不需要包装器。
Since you write Java classes with annotations, you could use this by adding (to Container) another "virtual" field and modify some annotations: 由于您编写带有注释的Java类,因此可以通过在容器中添加另一个“虚拟”字段并修改一些注释来使用此方法:
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Container {
// ...
@XmlTransient
public Map<String,Foo> getElements(){
return elements;
}
private List<Property> property;
@XMLElement
public List<Property> getProperty(){
List<Property> props = elements.entrySet().stream()
.map( e -> new Property( e.getKey(), e.getValue() )
.collect( Collectors.toList() );
return props;
}
Older Javas might do 较旧的Java可能会这样做
List<Property> props = new ArrayList<>();
for( Map.Entry<String,Foo> e: elements.entrySet() ){
props.add( new Property( e.getKey(), e.getValue() ) );
}
return props;
This marshals like this: 像这样的元帅:
<container>
<property name="aaa">
<foo name="aaaname" status="aaastatus"/>
</property>
<property name="bbb">
<foo name="bbbname" status="bbbstatus"/>
</property>
</container>
It doesn't unmarshal! 它不会解组!
Other than removing the tag by "hacking" the element name to be "", I don't think you're going to be able to get around using that data type without the nested tag. 除了通过“黑客”将元素名称更改为“”来删除标签之外,我认为您将无法在没有嵌套标签的情况下使用该数据类型。
The tag is describing the data type that encompasses your adapted class, which you've annotated as an XML element called elements
, which contains properties defined by your adapter. 标记描述的是包含已适配类的数据类型,该类已注释为一个名为elements
的XML elements
,其中包含适配器定义的属性。
If you want something that more closely matches what I think you are after, either change the context of your root class, or maybe use a List
instead of a HashMap
in your container class. 如果您想要更符合我的想法的东西,请更改根类的上下文,或者在容器类中使用List
而不是HashMap
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.