首页 > 解决方案 > 将 XML 解析为 Java 对象节点

问题描述

目前我在尝试将 xml 文档解析为 Java 对象时遇到问题。我想保留的唯一必要信息是iid时间列表。

xml测试文件:

    <items>
       <item>
        <iid>14</iid>
          <options>
              <option>
                <times>
                  <time>
                   <timeentry>20200714100100</timeentry>                           
                   <timetill>20200714101500</timetill>
                   <timemaxcount>2</timemaxcount>
                  </time>
                  <time>
                   <timeentry>20200714101600</timeentry>
                   <timetill>20200714103000</timetill>
                   <timemaxcount>2</timemaxcount>
                  </time>
                 <time>
                  <timeentry>20200714103100</timeentry>
                  <timetill>20200714104500</timetill>
                  <timemaxcount>2</timemaxcount>
                 </time>
                 <time>
                  <timeentry>20200714104600</timeentry>
                  <timetill>20200714110000</timetill>
                  <timemaxcount>2</timemaxcount>
                  </time
              </option>
          </options>
         </item>
      </items>

我创建了两个包含 iid 和时间列表的 Java 对象类。解析 xml 文件时,只有字段 iid 被填充并且列表对象为空。我错过了什么?

@JsonIgnoreProperties(ignoreUnknown = true)
@XmlRootElement(name = "item")
@JacksonXmlRootElement(localName = "item")
public class SubProduct implements Serializable {

    private String iid;

    @JacksonXmlElementWrapper(localName = "times")
    @JacksonXmlProperty(localName = "time")
    private List<TimePeriod> times;
}
@JsonIgnoreProperties(ignoreUnknown = true)
@JacksonXmlRootElement(localName = "time")
public class TimePeriod implements Serializable {
    @JsonProperty(value = "timeentry")
    String timeEntry;
    @JsonProperty(value = "timetill")
    String timeTill;
    @JsonProperty(value = "timemaxcount")
    String timeMaxCount;
}

服务层

...
NodeList itemList = document.getElementsByTagName("item"); 
List<SubProduct> subProducts = new ArrayList<>();
        for (int i = 0; i < nodes.getLength(); i++) {
            SubProduct value = xmlMapper.readValue(nodeToString(nodes.item(i)), SubProduct.class);
            subProducts.add(value);
            
        }
        return subProducts;

...

 public static String nodeToString(Node node) throws Exception{
        StringWriter sw = new StringWriter();

        Transformer t = TransformerFactory.newInstance().newTransformer();
        t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        t.setOutputProperty(OutputKeys.INDENT, "yes");
        t.transform(new DOMSource(node), new StreamResult(sw));

        return sw.toString();
    }

回应:

   {
        "iid": "9",
        "times": null
    },

标签: javaxmlparsingjacksonjackson-dataformat-xml

解决方案


你不需要混合JacksonJAXB上课Transformer。您可以直接将给定XML的有效负载反序列化为POJO模型。items,optionstimes节点代表List节点。我们可以将其映射到以下模型:

@Data
@ToString
class Item {
    private int iid;
    private List<Option> options;
}

@Data
@ToString
class Option {

    private List<Time> times;
}

@Data
@ToString
class Time {

    @JsonFormat(pattern = "yyyyMMddHHmmss")
    @JsonProperty("timeentry")
    private LocalDateTime entry;

    @JsonFormat(pattern = "yyyyMMddHHmmss")
    @JsonProperty("timetill")
    private LocalDateTime till;

    @JsonProperty("timemaxcount")
    private int maxCount;
}

我使用Lombok注释来避免样板代码。简单用法:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.Data;
import lombok.ToString;

import java.io.File;
import java.time.LocalDateTime;
import java.util.List;

public class XmlMapperApp {

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

        XmlMapper mapper = XmlMapper.xmlBuilder()
                .addModule(new JavaTimeModule())
                .build();
        List<Item> items = mapper.readValue(xmlFile, new TypeReference<List<Item>>() {
        });
        items.forEach(item -> {
            System.out.println("Id => " + item.getIid());
            System.out.println("Times => ");
            item.getOptions().stream().flatMap(o -> o.getTimes().stream())
                    .forEach(System.out::println);
        });
    }
}

上面的代码打印:

Id => 14
Times => 
Time(entry=2020-07-14T10:01, till=2020-07-14T10:15, maxCount=2)
Time(entry=2020-07-14T10:16, till=2020-07-14T10:30, maxCount=2)
Time(entry=2020-07-14T10:31, till=2020-07-14T10:45, maxCount=2)
Time(entry=2020-07-14T10:46, till=2020-07-14T11:00, maxCount=2)

也可以看看:


推荐阅读