JAXB / XSD:数字而不是元素名称

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

我必须从xml文件创建Java对象(我在转换之前无法编辑),所以我认为最好创建一个XSD,然后通过JAXB解组该文件。问题是,XML中有一些元素的格式如下:

<parent-element>
    <id-00001>...</id-00001>
    <id-00002>...</id-00002>
    ...
</parent-element>

所以基本上我有一个xml元素列表,元素的“名称”是列表中的顺序。每个列表中可能存在无限数量的元素。是否可以使用JAXB解组,或者我是否必须使用XML-Reader并遍历这些元素? “id-XXXXX”元素在内部以相同的方式进行格式化,因此如果将其格式化为“”,则可以没有任何问题。

提前致谢!

java xml xsd jaxb
2个回答
1
投票

我想你的XML有效载荷如下所示:

<root>
    <parent-element>
        <id-00001>value 1</id-00001>
        <id-00002>value 2</id-00002>
    </parent-element>
</root>

要读取具有动态名称的节点,我们需要编写自定义适配器(javax.xml.bind.annotation.adapters.XmlAdapter)。假设该模型如下所示:

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
class Root {

    @XmlElement(name = "parent-element")
    @XmlJavaTypeAdapter(IdsXmlAdapter.class)
    private MultiItemList list;

    // getters, setters, toString
}

class MultiItemList {

    private List<String> ids;

    // getters, setters, toString
}

对于上面的XMLPOJO模型定制适配器可能如下所示:

class IdsXmlAdapter extends XmlAdapter<Object, MultiItemList> {

    @Override
    public MultiItemList unmarshal(Object v) {
        Element element = (Element) v;
        NodeList childNodes = element.getChildNodes();
        List<String> ids = new ArrayList<>(childNodes.getLength());
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            if (item.getNodeName().equals("#text")) {
                continue;
            }
            ids.add(item.getTextContent());
        }

        MultiItemList multiItemList = new MultiItemList();
        multiItemList.setIds(ids);
        return multiItemList;
    }

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

用法示例:

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

import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
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.io.FileReader;
import java.util.ArrayList;
import java.util.List;

public class JaxbApp {

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

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

        Object unmarshal = jaxbContext.createUnmarshaller().unmarshal(new FileReader(xmlFile));
        System.out.println(unmarshal);
    }
}

打印:

Root{list=Root{ids=[value 1, value 2]}}

请注意,由于异常,您无法直接实现XmlAdapter<Element, MultiItemList>适配器:

Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.w3c.dom.Element is an interface, and JAXB can't handle interfaces.
    this problem is related to the following location:
        at org.w3c.dom.Element

也可以看看:


1
投票

由于您的xml可能具有无限数量的“id-elements”,因此创建匹配的POJO结构非常棘手。您可以使用@XmlAnyElement和适配器。 @XmlAnyElement会将各种元素读取为dom节点,您可以在适配器中处理它们。

例如,使用下面给出的xml:

<parent-element>
    <id-00001>value 1</id-00001>
    <id-00002>value 2</id-00002>
</parent-element>

您的root可能如下所示:

@XmlRootElement(name = "parent-element")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlAnyElement
    @XmlJavaTypeAdapter(MyAdapter.class)
    private List<String> varyingElements;

}

你的适配器是这样的:

public class MyAdapter extends XmlAdapter<Element, String> {

    @Override
    public Element marshal(String arg0) throws Exception {
        // do what you must
        return null;
    }

    @Override
    public String unmarshal(Element element) throws Exception {
        return element.getChildNodes().item(0).getNodeValue();
    }

}

元素在org.w3c.dom.Element

© www.soinside.com 2019 - 2024. All rights reserved.