【问题标题】:JAXB: Remove parent node keeping it's childrenJAXB:删除父节点保留其子节点
【发布时间】:2020-08-30 05:29:03
【问题描述】:

我知道这没有多大意义,但我必须从没有某些元素的父节点的 Java 对象生成 XML,如下所述。

这是 XML 的示例 Java 类模型:

@XmlRootElement(name = "person")
public class PersonXml {

    @XmlElement(name = "name")
    private String name;

    @XmlElement(name = "car")
    private List<CarXml> cars;

.

@XmlRootElement(name = "car")
public class CarXml {

    @XmlElement(name = "model")
    private String model;

    @XmlElement(name = "brand")
    private String brand;

默认情况下,如果我像这样从PersonXml 的对象生成 XML:

StringWriter writer = new StringWriter();

JAXBContext ctx = JAXBContext.newInstance(PersonXml.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.marshal(xml, writer);

我会得到:

<person>
    <name>Pedro</name>
    <car>
        <model>Logan</model>
        <brand>Renault</brand>
    </car>
    <car>
        <model>Duster</model>
        <brand>Renault</brand>
    </car>
</person>

我需要删除&lt;car&gt;标签,甚至完全阻止它生成。

我需要这样的 XML:

<person>
    <name>Pedro</name>
    <model>Logan</model>
    <brand>Renault</brand>
    <model>Duster</model>
    <brand>Renault</brand>
</person>

当然,我可以将 XML 转换为字符串并使用 replaceAll 或类似的东西删除标签,但我想知道是否有更好的方法来实现这一点。

【问题讨论】:

    标签: java xml jaxb marshalling


    【解决方案1】:

    如果需要生成这个输出,可以使用JAXB,如下:

    1) 创建一个新的Person 类:

    import java.util.ArrayList;
    import java.util.List;
    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElementRef;
    import javax.xml.bind.annotation.XmlElementRefs;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "field"
    })
    @XmlRootElement(name = "person")
    public class Person {
    
        @XmlElementRefs({
            @XmlElementRef(name = "name", type = JAXBElement.class, required = false),
            @XmlElementRef(name = "model", type = JAXBElement.class, required = false),
            @XmlElementRef(name = "brand", type = JAXBElement.class, required = false)
        })
        protected List<JAXBElement<String>> field;
    
        public List<JAXBElement<String>> getNameOrModelOrBrand() {
            if (field == null) {
                field = new ArrayList<>();
            }
            return this.field;
        }
    
    }
    

    2) 创建一个ObjectFactory 以更方便地使用person 类:

    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.annotation.XmlElementDecl;
    import javax.xml.bind.annotation.XmlRegistry;
    import javax.xml.namespace.QName;
    
    @XmlRegistry
    public class ObjectFactory {
    
        private final static QName _PersonName_QNAME = new QName("", "name");
        private final static QName _PersonModel_QNAME = new QName("", "model");
        private final static QName _PersonBrand_QNAME = new QName("", "brand");
    
        public ObjectFactory() {
        }
    
        public Person createPerson() {
            return new Person();
        }
    
        @XmlElementDecl(namespace = "", name = "name", scope = Person.class)
        public JAXBElement<String> createPersonName(String value) {
            return new JAXBElement<>(_PersonName_QNAME, String.class, Person.class, value);
        }
    
        @XmlElementDecl(namespace = "", name = "model", scope = Person.class)
        public JAXBElement<String> createPersonModel(String value) {
            return new JAXBElement<>(_PersonModel_QNAME, String.class, Person.class, value);
        }
    
        @XmlElementDecl(namespace = "", name = "brand", scope = Person.class)
        public JAXBElement<String> createPersonBrand(String value) {
            return new JAXBElement<>(_PersonBrand_QNAME, String.class, Person.class, value);
        }
    
    }
    
    1. 使用工厂如下:
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.Marshaller;
    import java.io.StringWriter;
    import java.util.List;
    
    ...
    
    ObjectFactory factory = new ObjectFactory();
    
    Person person = factory.createPerson();
    List<JAXBElement<String>> list = person.getNameOrModelOrBrand();
    list.add(factory.createPersonName("Pedro"));
    list.add(factory.createPersonModel("Logan"));
    list.add(factory.createPersonBrand("Renault"));
    list.add(factory.createPersonModel("Duster"));
    list.add(factory.createPersonBrand("Renault"));
    
    JAXBContext ctx = JAXBContext.newInstance(Person.class);
    Marshaller marshaller = ctx.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    StringWriter writer = new StringWriter();
    marshaller.marshal(person, writer);
    System.out.println(writer.toString());
    

    最终得到的XML如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <person>
        <name>Pedro</name>
        <model>Logan</model>
        <brand>Renault</brand>
        <model>Duster</model>
        <brand>Renault</brand>
    </person>
    

    以这种方式创建元素是我所知道的获得所需最终结果的唯一方法。

    您可能可以做各种事情来重构上述代码,以简化元素列表的创建 - 但这向您展示了基本方法。

    如您所知 - 这远非理想。最终结果不是我想要接收的任何类型的 XML。

    【讨论】:

    • 你能看看这个例子并提供类似的解决方案吗?我想为用户定义的数据删除XML 中的Nodename。在这些情况下,一切都是自定义的,由用户提供。我在这里发布了这个问题,如果你有机会请看一下并提供你的回复:stackoverflow.com/q/67648941/7584240
    猜你喜欢
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2013-02-04
    相关资源
    最近更新 更多