解组 JAXB 时动态标记值为空(基于 http://stackoverflow.com/a/26328873/3838


package dogs;
@XmlRootElement(name = "dog")
public class Dog extends JAXBElement<String>{
    public static final QName NAME = new QName("dog");
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String dogName;
    private String sound;
    public Dog(String name) {
        super(NAME, String.class, name);
    }
    public Dog(String dogName, String sound) {
        super(NAME, String.class, sound);
        this.dogName = dogName;
    }
    @Override
    public QName getName() {
        final String name = getDogName();
        if(name != null) {
            return new QName(name);
        }
        return NAME;
    }
    public String getDogName() {
        return dogName;
    }
    public void setDogName(String dogName) {
        this.dogName = dogName;
    }
    public String getSound() {
        return sound;
    }
    public void setSound(String sound) {
        this.sound = sound;
    }
    @Override
    public String toString() {
        return "Dog [dogName=" + dogName + ", sound=" + sound + "]";
    }
}

package dogs;

@XmlRootElement(name = "listOfDogs")
public class Dogs {
    private List<Object> dogs;
    @XmlMixed
    @XmlAnyElement
    @XmlElementWrapper(name = "dogs")
    public List<Object> getDogs() {
        return this.dogs;
    }
    public void setDogs(List<Object> dogs) {
        this.dogs = dogs;
    }
    public static void main(String[] args) throws JAXBException, FileNotFoundException, XMLStreamException {
        JAXBContext context = JAXBContext.newInstance(Dogs.class);
        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("dogs2.xml"));
        xsr = new MyStreamReaderDelegate(xsr);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Dogs dogs = (Dogs) unmarshaller.unmarshal(xsr);
        System.out.println(dogs.getDogs());
    }
    private static class MyStreamReaderDelegate extends StreamReaderDelegate {
        public MyStreamReaderDelegate(XMLStreamReader xsr) {
            super(xsr);
        }
        @Override
        public String getAttributeLocalName(int index) {
            return super.getAttributeLocalName(index);
        }
        @Override
        public String getLocalName() {
            if(super.getLocalName().equals("dog")) {
                try {
                    super.nextTag();
                } catch (XMLStreamException e) {
                    e.printStackTrace();
                }
            }
            return super.getLocalName();
        }
    }
    @Override
    public String toString() {
        return "Dogs [dogs=" + dogs + "]";
    }
}

狗2.xml文件是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<listOfDogs>
    <dogs>
        <dog>
            <name>Henry</name>
            <sound>Bark</sound>
        </dog>
    </dogs>
</listOfDogs>

上述代码的结果是:

[[name: null], [sound: null]]

但它应该是:

[Dog [dogName=Henry, sound=Bark]]

如您所见,没有调用类 Dog 中的 toString(( 方法。我尝试从 JAXBElement 覆盖 getValue(( 以返回类 Dog 中的声音,但没有结果,因为它没有被调用。解组时不会调用 Dog 类中的任何内容。而不是列出狗,我宁愿有列表狗,这样我就可以从某个索引中获取所有狗并调用 getDogName(( 和 getSound((;我已经阅读了很多关于这个主题的帖子,但我找不到可以帮助我的东西。

我哪里做错了?还有其他选择吗?

解决方案 1 - 根据您的 xml 文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<listOfDogs>
    <dogs>
        <dog>
            <name>Henry</name>
            <sound>Bark</sound>
        </dog>
    </dogs>
</listOfDogs>
@XMLRootElement(name="listOfDogs")
class ListOfDogs {
    private Dogs dogs;
    //Getters and Setters
    @Override
    public String toString(){
        return dogs + "";
    }
}
@XMLRootElement(name="dogs")
class Dogs {
    List<Dog> dogs;
    @XMLElement(name="dog")
    public List<Dog> getDogs() {
        return dogs;
    }
    //Setters
   @Override
   public String toString() {
       return dogs + "";
   }
}
@XmlRootElement(name = "dog")
public class Dog {
    private String dogName;
    private String sound;
    @XmlElement(name = "name")
    public String getDogName() {
        return dogName;
    }
    public void setDogName(String dogName) {
        this.dogName = dogName;
    }
    public String getSound() {
        return sound;
    }
    public void setSound(String sound) {
        this.sound = sound;
    }
    @Override
     public String toString() {
        return "Dog[" + "dogName=" + dogName + ", sound=" + sound + ']';
     }
}

解决方案 2 :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dogs>
    <dog>
        <name>Henry</name>
        <sound>Bark</sound>
    </dog>
</dogs>

使用此解决方案,不再使用 ListOfDogs 类。您可以将其删除。

这不是一个答案,而是一个声明,我无法让它工作。无论如何,我都会报告,因为我认为这可能是一个有价值的投入。

我的想法是实现一个ObjectFactory,每个狗名都有一个方法:

@XmlRegistry
public class ObjectFactory {
    public Dogs createDogs() {
        return new Dogs();
    }
    @XmlElementDecl(name = "dog")
    public Dog createDog(DogType value) {
        return new Dog(value);
    }
    @XmlElementDecl(name = "fido", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public Dog createFido(DogType value) {
        return new Dog("fido", value);
    }
    @XmlElementDecl(name = "barks", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public Dog createBarks(DogType value) {
        return new Dog("barks", value);
    }
}

我实际上已经预料到这些createBarkscreateFido方法将在解组期间调用。这将在DogType实例中设置狗名。老实说,我很惊讶没有调用这些方法。

但是,在解组期间不会调用这些方法,因此我无法获得真正的标记名称。

我的想法没有奏效。如果有人想尝试,这里是我的代码。

在我的测试中,未设置名称:

    @Test
    public void unmarshallsDogs() throws JAXBException {
        final JAXBContext context = JAXBContext
                .newInstance(ObjectFactory.class);
        final Dogs dogs = (Dogs) context.createUnmarshaller().unmarshal(
                getClass().getResource("dogs.xml"));
        Assert.assertEquals(3, dogs.getDogs().size());
        // Does not work
//      Assert.assertEquals("henry", dogs.getDogs().get(0).getValue()
//              .getName());
        Assert.assertEquals("bark", dogs.getDogs().get(0).getValue().getSound());
        // Does not work
//      Assert.assertEquals("fido", dogs.getDogs().get(1).getValue()
//              .getName());
        Assert.assertEquals("woof", dogs.getDogs().get(1).getValue().getSound());
        // Does not work
//      Assert.assertEquals("barks", dogs.getDogs().get(2).getValue()
//              .getName());
        Assert.assertEquals("miau", dogs.getDogs().get(2).getValue().getSound());
    }

请参阅Blaise Doughan的答案,以获取基于XmlAdapter的解决方案。

相关内容

最新更新