Динамические атрибуты XML с JAXB - PullRequest
0 голосов
/ 06 апреля 2019

У меня есть XML файл, который я пытаюсь разобрать в java-объект, используя JAXB

<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>

1 Ответ

1 голос
/ 06 апреля 2019

Вам нужно написать собственный адаптер, который расширяет класс 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}]}
...