使用JAXB的动态XML属性

问题描述 投票:0回答:1

我有一个XML文件,我试图使用JAXB解组为java对象

<root>
    <object att1="orgA" att2="orgA" id="6" name="">
        ...
    </object>
</root>

Java类:

@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@XmlRootElement(name="object")
public class ObjectElement implements Serializable {

@XmlAttribute
private int id;

@XmlAttribute
private String attr1;

@XmlAttribute
private String attr2;

@XmlAttribute
private String name;

}

问题:xml元素object的属性可能会动态更改。因此,属性的键可能是动态的,因此无法将它们作为XmlAttributes放在课堂上。有没有办法定义某种HashMap读取object的所有键和相应的值?例如,新对象可能具有完全不同的属性,如下所示;

<object att5="some" att7="other" id="6" name="value">
    ...
</object>
java jackson jaxb deserialization xml-deserialization
1个回答
1
投票

您需要编写扩展javax.xml.bind.annotation.adapters.XmlAdapter类的自定义适配器。在您的情况下,我们可以创建一个代表所有属性的Map。读取属性后,您可以使用反射或手动设置所有POJO字段。自动反序列化器可以动态读取所有属性,如下所示:

class ItemXmlAdapter extends XmlAdapter<Object, Item> {

    @Override
    public Item unmarshal(Object v) {
        Element element = (Element) v;

        Map<String, String> properties = new HashMap<>();
        NamedNodeMap attributes = element.getAttributes();
        for (int i = attributes.getLength() - 1; i >= 0; i--) {
            Node node = attributes.item(i);
            properties.put(node.getNodeName(), node.getNodeValue());
        }

        Item item = new Item();
        item.setProperties(properties);

        return item;
    }

    @Override
    public Object marshal(Item v) throws Exception {
        return null; // Implement if needed
    }
}

简单的示例应用程序,它读取XML并解析所有属性:

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JaxbApp {

    public static void main(String[] args) throws Exception {
        File xmlFile = new File("./resource/test.xml").getAbsoluteFile();

        JAXBContext context = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = context.createUnmarshaller();
        Root root = (Root) unmarshaller.unmarshal(xmlFile);

        System.out.println(root);
    }
}

@XmlRootElement(name = "root")
class Root {

    private List<Item> items = new ArrayList<>();

    @XmlElement(name = "object")
    public List<Item> getItems() {
        return items;
    }

    // getters, setters, toString
}

@XmlJavaTypeAdapter(ItemXmlAdapter.class)
class Item {

    private Map<String, String> properties;

    // getters, setters, toString
}

对于XML以下:

<root>
    <object att1="orgA" att2="orgA" id="6" name="N"/>
    <object att5="some" id="6" name="value"/>
</root>

打印:

Items{items=[{name=N, id=6, att2=orgA, att1=orgA}, {name=value, att5=some, id=6}]}
© www.soinside.com 2019 - 2024. All rights reserved.