使用JAXB进行多态XML绑定

时间:2014-11-16 02:05:12

标签: java xml jaxb

以下是我要做的事情:

XML就是这样:

<Doctype1>
    <Outter>
        <Inner>
          <ProblemType>
              <foo>...</foo>
              <baz>...</baz>
          </ProblemType>
        </Inner>
    </Outter>
</Doctype1>

&lt; - 但是,我有: - &gt;

<Doctype2>
    <Outter>
        <Inner>
          <ProblemType>
              <blah>...</blah>
              <whatever>...</whatever>
          </ProblemType>
        </Inner>
    </Outter>
</Doctype1>

和 分享大多数相同的字段,但在Doctype1的情况下,我需要ProblemType1,在Doctype2中,我需要ProblemType2。

我希望能够重用我绑定的类,因为它们是所有doc类型的通用标记。

@XmlAccessorType(XmlAccessType.FIELD)
public class Doc1{

    @XmlElement(name = "Outter")
    public List<Outter> outtards;

}

@XmlAccessorType(XmlAccessType.FIELD)
public class Outter {

    @XmlElement(name = "Inner")
    public List<Innard> innards;
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Innard{

    // need to change this if it's Doc1 or Doc2. 
    //The subtype of problem type needs to change based on DocX
    // the element type name won't change
    @XmlElement(name = "Inner")
    public ProblemType subtype; 
}

似乎也许工厂井然有序?

@XmlType(factoryClass= , factoryMethod=) 

3 个答案:

答案 0 :(得分:1)

首先,您将如何在Java中实现这样的结构? DoctypeXProblemTypeX之间有一段距离,因此您无法直接进行多边形。

可能有类似(非常伪代码)的结构:

class AbstractDoctype {
  AbstractOuter getOuter();
}
class AbstractOuter {
  AbstractInner getInner();
}
class AbstractInner {
  AbstractProblemType getProblemType();
}
class AbstractProblemType {
}

class Doctype1 extends AbstractDoctype  {
  Outer1 getOuter();
}
class Outer1 extends AbstractOuter {
  Inner1 getInner();
}
class Inner1 extends AbstractInner {
  ProblemType1 getProblemType();
}
class ProblemType1 extends AbstractProblemType {
}

class Doctype2 extends AbstractDoctype  {
  Outer2 getOuter();
}
class Outer2 extends AbstractOuter {
  Inner2 getInner();
}
class Inner2 extends AbstractInner {
  ProblemType2 getProblemType();
}
class ProblemType2 extends AbstractProblemType {
}

这种结构适用于您的XML。您可以使用Outer1来避免Outer2 / @XmlElementWrapper,但仍需要Inner1 / Inner2

答案 1 :(得分:1)

  @XmlAccessorType(XmlAccessType.NONE)
    public class Doc1 {

        @XmlElement(type = Outter1.class, name = "Outter")
        private List<Outter> outters;

        public static class Outter1 extends Outter {

            @Override
            @XmlElement(type = Inner1.class, name = "Inner")
            public List<Inner> getInner() {
                return super.getInner();
            }

            @Override
            public void setInner(List<Inner> innards) {
                super.setInner(innards);
            }

            public static class Inner1 extends Inner<ProblemType1> {

                @Override
                @XmlElement(type = ProblemType1.class, name = "ProblemType")
                public List<ProblemType> getProblemTypes() {
                    return super.getProblemTypes();
                }

                @Override
                public void setProblemTypes(List<ProblemType> problemTypes) {
                    super.setProblemTypes(problemTypes);
                }
            }
        }
    }

其他班级

public class Doc2 {

    @XmlElement(type = Outter2.class, name= "Outter")
    private List<Outter> outters;

    public static class Outter2 extends Outter {

        @Override
        @XmlElement(type = Outter2.class, name = "Inner")
        public List<Inner> getInner() {
            return super.getInner();
        }

        @Override
        public void setInner(List<Inner> innards) {
            super.setInner(groups);
        }

        public static class Inner1 extends Inner<ProblemType2> {
            @Override
            @XmlElement(type = ProblemType2.class, name = "ProblemType")
            public List<ProblemType> getProblemTypes() {
                return super.getProblemTypes();
            }

            @Override
            public void setProblemTypes(List<ProblemType> transactions) {
                super.setProblemTypes(transactions);
            }
        }
    }
}

我花了一些时间尝试减少它,但它似乎没有响应XmlAccesorType.FIELD。如果我使用与超级相同的属性名称,则无关紧要。

答案 2 :(得分:0)

这是this answer的后续行动,试图用@XmlElementWrapper保存几行。由于Outter类似乎没有任何意义,它只作为Inner类的容器,因此可以避免:

请尝试以下方法:

@XmlAccessorType(XmlAccessType.NONE)
public class Doc1 {

        @XmlElementWrapper(name = "Outter")
        @XmlElement(type = Inner1.class, name = "Inner")
        public List<Inner> getInner() {
            return super.getInner();
        }

        @Override
        public void setInner(List<Inner> innards) {
            super.setInner(innards);
        }

        public static class Inner1 extends Inner<ProblemType1> {

            @Override
            @XmlElement(type = ProblemType1.class, name = "ProblemType")
            public List<ProblemType> getProblemTypes() {
                return super.getProblemTypes();
            }

            @Override
            public void setProblemTypes(List<ProblemType> problemTypes) {
                super.setProblemTypes(problemTypes);
            }
        }
}

但请注意,这个现在只有一个列表,而不是列表列表。所以这个构造仍然可以实现:

<Doctype1>
    <Outter>
        <Inner>
          <ProblemType .../>
        </Inner>
        <Inner>
          <ProblemType .../>
        </Inner>
    </Outter>
</Doctype1>

但这不是:

<Doctype1>
    <Outter>
        <Inner>
          <ProblemType .../>
        </Inner>
    </Outter>
    <Outter>
        <Inner>
          <ProblemType .../>
        </Inner>
    </Outter>
</Doctype1>