如何在杰克逊中反嵌套化多个嵌套元素? [英] How to deserealize multiple nested elements in Jackson?

查看:98
本文介绍了如何在杰克逊中反嵌套化多个嵌套元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要构建一个解析器以将XML文件解析为Java对象. 我使用Jackson来执行此操作,并遵循教程.

I need to build a parser to parse an XML file to a Java object. I use Jackson to do this and followed the steps provided in THIS tutorial.

本教程中的"操纵XML中的嵌套元素和列表"部分.我遵循了它,但是不幸的是我无法获得所有必需元素的期望输出-我想首先输出所有作者的文章.而且我只能在XML -file中为我的最后一位作者得到它:

In the tutorial is a section 'Manipulating Nested Elements and Lists in XML'. I followed it, but unfortunately I can't get the desired output of all my required elements - I want to output first and last of all my authors. And I only get it for my last author in the XML-file like this:

[{nameList={person={first=Karl, last=S}}}]

我的XML文件如下所示.

<sources>
<Doi>123456789</Doi>
<Title>Title</Title>
<author>
    <editor>
        <nameList>
            <person>
                <first>Peter</first>
                <last>Parker</last>
            </person>
        </nameList>
    </editor>
</author>
<Source>
    <SourceType>Book</SourceType>
    <ShortTitle>Book Title</ShortTitle>
    <Author>
        <Editor>
            <NameList />
        </Editor>
    </Author>
</Source>
<author>
    <bookAuthor>
        <nameList>
            <person>
                <first>Karl</first>
                <last>S</last>
            </person>
        </nameList>
    </bookAuthor>
</author>
<Source>
    <SourceType>Journal</SourceType>
    <ShortTitle>ABC Journal</ShortTitle>
</Source>
</sources>

如何重新散化整个XML文件?

How can I deserealize the entire XML file?

我的代码如下: MyClass.java

My code looks like this: MyClass.java

private static void jacksonXmlFileToObject() throws IOException {

    System.out.println("jacksonXmlFileToObject");

    InputStream xmlFile = Publication.class.getClassLoader().getResourceAsStream("test.xml");
    ObjectMapper mapper = new XmlMapper();

    // Configure
    mapper
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    try {

        Sources deserializedData = mapper.readValue(xmlFile, Sources.class);

        System.out.println(deserializedData);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Sources.java

Sources.java

@EqualsAndHashCode
@JacksonXmlRootElement(localName = "sources") public class Sources {
@JacksonXmlElementWrapper(localName = "author")
@Getter
@Setter
private Object[] author;

@Override
public String toString() {
    return Arrays.toString(author);
}

public Sources() {
}
}

我会很高兴获得一些帮助.

I would be very happy about some help.

谢谢!

推荐答案

当相同的元素彼此不跟随时,JacksonXmlElementWrapper似乎不起作用.常规XML应该包含一个又一个列出的相同节点.当其他节点启动时,意味着上一个节点部分已完成.为了处理您的情况,我们需要编写自定义反序列化器:手动读取所有作者,并跳过其余节点.示例代码可能如下所示:

It looks like JacksonXmlElementWrapper does not work when the same elements are not following each other. Regular XML should contain the same nodes listed one after another. When other node starts it's mean previous node section is finished. To handle your case we need to write custom deserialiser: manually read all authors and skip the rest of nodes. Example code could look like this:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
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 = new XmlMapper();

        System.out.println(mapper.readValue(xmlFile, Sources.class));
    }
}

class SourcesJsonDeserializer extends JsonDeserializer<Sources> {

    private final JsonPointer EDITOR = JsonPointer.compile("/editor/nameList/person");
    private final JsonPointer BOOK_AUTHOR = JsonPointer.compile("/bookAuthor/nameList/person");

    @Override
    public Sources deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        List<JsonNode> authors = new ArrayList<>();
        JsonToken token;
        while ((token = p.currentToken()) != null) {
            if (token == JsonToken.FIELD_NAME) {
                if ("author".equals(p.getText())) {
                    authors.add(getPersonObject(p));
                }
            }
            p.nextToken();
        }

        Sources sources = new Sources();
        sources.setAuthors(authors);

        return sources;
    }

    private JsonNode getPersonObject(JsonParser p) throws IOException {
        // read start object
        p.nextToken();

        // read the whole object as node
        ObjectNode author = p.readValueAsTree();

        // try to evaluate /editor/* path
        JsonNode pair = author.at(EDITOR);
        if (pair.isMissingNode()) {
            // must be bookAuthor
            pair = author.at(BOOK_AUTHOR);
        }

        return pair;
    }
}

@JsonDeserialize(using = SourcesJsonDeserializer.class)
class Sources {

    private List<JsonNode> authors;

    public List<JsonNode> getAuthors() {
        return authors;
    }

    public void setAuthors(List<JsonNode> authors) {
        this.authors = authors;
    }

    @Override
    public String toString() {
        return authors + "";
    }
}

上面的代码显示:

[{"first":"Peter","last":"Parker"}, {"first":"Karl","last":"S"}]

这篇关于如何在杰克逊中反嵌套化多个嵌套元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆