如何在不创建包装类的情况下编组Jaxb元素列表?

时间:2016-02-16 22:47:04

标签: java xml jaxb

没有实际编写一个编写器并将每个元素附加到字符串上。有没有办法让JAXB marshaller编组一个对象列表,我可以给它一个顶级元素的名称?

我觉得我很接近这个

//http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
public <T> String jaxb(Collection<T> o, Class<T> clazz, String plural){
    try {
        ArrayList<T> al = new ArrayList<T>(o.size());
        al.addAll(o);
        JAXBContext jc = JAXBContext.newInstance(ArrayList.class);
        JAXBElement<ArrayList> amenity = new JAXBElement(new QName(plural), ArrayList.class, al);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        StringWriter writer = new StringWriter();
        marshaller.marshal(amenity, writer);
        return writer.toString();
    } catch (JAXBException e) {
        throw new RuntimeException(e);
    }
}

但结果仍然以空列表的形式返回

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<pluralName/>

有没有办法在不手动粘贴xml字符串的情况下执行此操作?

更新

在Michael Glavassevich的帮助下,我已经能够做到这一点,但有一个警告,个别元素是<Item> s

//http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
@SuppressWarnings({ "unchecked", "rawtypes" })
public <T> String jaxb(Collection<T> elements, Class<T> elementClass, String plural){
    try {
        T[] array = (T[]) Array.newInstance(elementClass, elements.size());
        elements.toArray(array);
        JAXBContext jc = JAXBContext.newInstance(array.getClass());
        JAXBElement<T[]> topElement = new JAXBElement(new QName(plural), array.getClass(), array);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        StringWriter writer = new StringWriter();
        marshaller.marshal(topElement, writer);
        return writer.toString();
    } catch (JAXBException e) {
        throw new RuntimeException(e);
    }
}

结果变为

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Basketballs>
    <item>basketball one</item>
    <item>basketball two</item>
</Basketballs>

4 个答案:

答案 0 :(得分:4)

如果您不想创建包装类,可以将该集合转换为数组,将该数组放在JAXBElement中,然后封送它。

例如:

public class JAXBArrayWriter {

    public static class Item {
        @XmlValue
        protected String value;

        public Item() {}

        public Item(String value) {
            this.value = value;
        }
    }

    public static void main (String [] args) throws Exception {
        List<Item> items = new ArrayList<Item>();
        items.add(new Item("one"));
        items.add(new Item("two"));
        JAXBContext jc = JAXBContext.newInstance(Item[].class);
        JAXBElement<Item[]> root = new JAXBElement<Item[]>(new QName("items"), 
                Item[].class, items.toArray(new Item[items.size()]));
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        StringWriter writer = new StringWriter();
        marshaller.marshal(root, writer);
        System.out.println(writer.toString());
    }
}

产生以下文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<items>
    <item>one</item>
    <item>two</item>
</items>

答案 1 :(得分:2)

请试试这个:

首先,创建一个列表类:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class AmenityList {
    @XmlElement(name = "amenity")
    List<Amenity> amenities = new ArrayList<Amenity>();

    public AmenityList() {}

    public void setList(List<Amenity> amenities) {
        this.amenities = amenities;
    }
}

然后是Amenity类:

@XmlAccessorType(XmlAccessType.FIELD)
class Amenity {
    private String amenityName;
    private String amenityDate;

    public Amenity(String name, String date) {
        this.amenityName = name;
        this.amenityDate = date;
    }
}

在列表中设置您需要的设施 - 可能是一种不那么冗余的方式:) - 并将其分配给AmenityList:

AmenityList amenityList = new AmenityList();
List <Amenity> amenities = new ArrayList<Amenity>();
amenities.add(new Amenity("a_one", "today"));
amenities.add(new Amenity("a_two", "tomorrow"));
amenity.setList(amenities);

最后是一个toXml方法:

public static String toXml(AmenityList amenityList) throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(AmenityList.class);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    StringWriter sw = new StringWriter();
    jaxbMarshaller.marshal(amenityList, sw);
    return sw.toString()
}

获得,即:

<amenityList>
    <amenity>
        <amenityName>a_one</amenityName>
        <amenityDate>today</amenityDate>
    </amenity>
    <amenity>
        <amenityName>a_two</amenityName>
        <amenityDate>tomorrow</amenityDate>
    </amenity>
</amenityList>

答案 2 :(得分:0)

尝试一下。

POJO类:

.about-image {
  /*position: relative;
  display: inline-block; /* Make the width of box same as image */
  float: right;
  z-index:1;
  margin-top: 75px;
  margin-bottom: 75px;
  margin-right: 30px;
  }
  .about-image .overlay {
    font-family: "Raleway", "";
    /*
    position: absolute;
    */
  bottom: 0px;
  left: 0px;
        background: rgba(0, 0, 0, 0.8);
        font-family: Arial,sans-serif;
        color: #fff;
        width: 100%; /* Set the width of the positioned div */
        height: 5%;
  }
  .overlay a {
    text-decoration: none;
    color: #fff;
    font-family: "Raleway", "";
    text-align: left;
  }
  .overlay a:hover {
    color: #941313;
    transition: linear .4s;
  }

  .further h1 {
    color: black;
    font-family: "Raleway", "";
    font-weight: bold;
    font-size: 40px;
    padding-top: 75px;
    padding-right: 10px;
    padding-left: 70px;
  
  }
  .further h2 {
    color: black;
    font-family: "Raleway", "";
    font-weight: bold;
    font-size: 38px;
    padding-right: 80px;
    padding-left: 70px;
  }

  .further {
    overflow: hidden;
  }
  @media screen and (max-width: 640px) {
  .about-image {
    justify-content: center;
    display: inline-block;
  }
  .further h1 {
    padding-top: 200px;
    display: inline;
  }
  }

马歇尔代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Title</title>

 
  <meta charset="utf-8" />

  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />

<div class="about-image">
      <img class="resist" src="https://images.unsplash.com/photo-1554629947-334ff61d85dc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=376&q=80" width= "340px"
      height= "480px"/>
      <div class="overlay">
        <a href="about.html">Caption</a>
      </div>
    </div>

  <div class="further">
    <h1>
    Information written here</h1>
      <h2> ⇨ More Information </h2>
      <h2>  ⇨ More Information</h2>
      
  
    </div>

  

Xml结果:

@XmlRootElement(name = "classNameTAG")
@XmlAccessorType(XmlAccessType.FIELD)
public class ClassName {

    @XmlElementWrapper(name="listTAG")
    @XmlElement(name="itemTAG") 
    private List<ClassItem> items;
}

对我有用。

答案 3 :(得分:-1)

数组所接受的解决方案有效但会导致每个内部元素被命名:&lt; item&gt;

以下从此链接中获得的解决方案对我来说效果更好:

Is it possible to programmatically configure JAXB?

public class Wrapper<T> {

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

@XmlAnyElement(lax=true)
public List<T> getItems() {
    return items;
}

}

//JAXBContext is thread safe and so create it in constructor or 
//setter or wherever:
... 
JAXBContext jc = JAXBContext.newInstance(Wrapper.class, clazz);
... 

public String marshal(List<T> things, Class clazz) {

  //configure JAXB and marshaller     
  Marshaller m = jc.createMarshaller();
  m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

  //Create wrapper based on generic list of objects
  Wrapper<T> wrapper = new Wrapper<T>(things);
  JAXBElement<Wrapper> wrapperJAXBElement = new JAXBElement<Wrapper>(new QName(clazz.getSimpleName().toLowerCase()+"s"), Wrapper.class, wrapper);

  StringWriter result = new StringWriter();
  //marshal!
  m.marshal(wrapperJAXBElement, result);

  return result.toString();

}

它不需要将列表转换为数组,但需要1个通用通用类。