问题 如何使用JAXB解组重复的嵌套类?


如何指示JAXB处理此问题?

XML

<root>
 <parent>
    <child id="1" name="foo" />
 </parent>
 <parent>
    <child id="3" name="foo2" />
 </parent>
 <parent>
    <child id="4" name="bar2" />
 </parent>
 <parent>
    <child id="2" name="bar" />
 </parent>
</root>

Root.java

@XmlRootElement
public class Root {
   @XmlElement(name="parent/child")
   List<Child> allChildren;
}

这不起作用... allChildren是空的。


2218
2017-12-20 15:40


起源



答案:


您可以更改模型并执行以下操作:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
   @XmlElement(name="parent")
   List<Parent> allParents;
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
   @XmlElement(name="child")
   List<Child> allChildren;
}

UPDATE

是否可以避免父类?

有几种不同的方法可以实现这一目标:

选项#1 - 使用XmlAdapter的任何JAXB实现

您可以使用XmlAdapter虚拟添加 Parent 类。

ChildAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ChildAdapter extends XmlAdapter<ChildAdapter.Parent, Child> {

    public static class Parent {
        public Child child;
    }

    @Override
    public Parent marshal(Child v) throws Exception {
        Parent parent = new Parent();
        parent.child = v;
        return parent;
    }

    @Override
    public Child unmarshal(Parent v) throws Exception {
        return v.child;
    }

}

@XmlJavaTypeAdapter 注释用于引用 XmlAdapter

import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

   @XmlElement(name="parent")
   @XmlJavaTypeAdapter(ChildAdapter.class)
   List<Child> allChildren;

}

儿童

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Child {

    @XmlAttribute
    int id;

    @XmlAttribute
    String name;

}

选项#2 - 使用EclipseLink JAXB(MOXy)

如果你正在使用 EclipseLink JAXB(MOXy) 身为你的 JAXB(JSR-222) 实现然后你可以做以下(注意:我是MOXy领导):

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

   @XmlElement(name="parent")
   List<Child> allChildren;

}

儿童

莫西的 @XmlPath 注释的工作方式与您尝试使用的方式非常相似 @XmlElement 你的帖子中的注释。

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class Child {

    @XmlPath("child/@id")
    int id;

    @XmlPath("child/@name")
    String name;

}

了解更多信息


13
2017-12-20 15:47



是否可以避免父类? - Stephan
+1当我独立提出与该领域公认的专家完全相同的解决方案时,它总是让人放心:-) - Ian Roberts
@IanRoberts - I + 1你的答案:)。 - Blaise Doughan


答案:


您可以更改模型并执行以下操作:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
   @XmlElement(name="parent")
   List<Parent> allParents;
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
   @XmlElement(name="child")
   List<Child> allChildren;
}

UPDATE

是否可以避免父类?

有几种不同的方法可以实现这一目标:

选项#1 - 使用XmlAdapter的任何JAXB实现

您可以使用XmlAdapter虚拟添加 Parent 类。

ChildAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ChildAdapter extends XmlAdapter<ChildAdapter.Parent, Child> {

    public static class Parent {
        public Child child;
    }

    @Override
    public Parent marshal(Child v) throws Exception {
        Parent parent = new Parent();
        parent.child = v;
        return parent;
    }

    @Override
    public Child unmarshal(Parent v) throws Exception {
        return v.child;
    }

}

@XmlJavaTypeAdapter 注释用于引用 XmlAdapter

import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

   @XmlElement(name="parent")
   @XmlJavaTypeAdapter(ChildAdapter.class)
   List<Child> allChildren;

}

儿童

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Child {

    @XmlAttribute
    int id;

    @XmlAttribute
    String name;

}

选项#2 - 使用EclipseLink JAXB(MOXy)

如果你正在使用 EclipseLink JAXB(MOXy) 身为你的 JAXB(JSR-222) 实现然后你可以做以下(注意:我是MOXy领导):

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

   @XmlElement(name="parent")
   List<Child> allChildren;

}

儿童

莫西的 @XmlPath 注释的工作方式与您尝试使用的方式非常相似 @XmlElement 你的帖子中的注释。

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class Child {

    @XmlPath("child/@id")
    int id;

    @XmlPath("child/@name")
    String name;

}

了解更多信息


13
2017-12-20 15:47



是否可以避免父类? - Stephan
+1当我独立提出与该领域公认的专家完全相同的解决方案时,它总是让人放心:-) - Ian Roberts
@IanRoberts - I + 1你的答案:)。 - Blaise Doughan


您将不得不创建一个代表该类的类 <parent> 元素,如

@XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
   @XmlElement(name="child")
   Child child;
}

然后,您可以创建一个类型适配器

public class ParentToChildAdapter extends XmlAdapter<Parent, Child> {
  public Parent marshal(Child c) {
    Parent p = new Parent();
    p.child = child;
    return p;
  }

  public Child unmarshal(Parent p) {
    return p.child;
  }
}

并在根类上使用它

@XmlRootElement
public class Root {
   @XmlElement(name="parent")
   @XmlJavaTypeAdapter(ParentToChildAdapter.class)
   List<Child> allChildren;
}

2
2017-12-20 16:14





你可以尝试使用 XmlElementWrapper 注释但我不确定它应该如何与多个包装器节点一起使用:

@XmlRootElement
public class Root {
   @XmlElementWrapper(name="parent")
   @XmlElement(name="child")
   List<Child> allChildren;
}

1
2017-12-20 15:46



我只有一个孩子而不是所有孩子。 - Stephan


尝试这个

@XmlRootElement
class Root {
    List<Child> allChildren = new ArrayList<Child>();

    private static class Parent  {
        @XmlElement
        Child child;
    }

    @XmlElement
    public void setParent(Parent p) {
        allChildren.add(p.child);
    }
}

0
2017-12-20 16:00



是的,他做了,但这里的父母只是一个技巧,只是一个私人课程。最重要的是我们有List <Child> not List <Parent> - Evgeniy Dorofeev