【问题标题】:How to parse xml file containing multiple tags using LinkedHashMap?如何使用 LinkedHashMap 解析包含多个标签的 xml 文件?
【发布时间】:2019-12-09 08:24:28
【问题描述】:

我想构建一个解析器来解析Java 中的XML 文件。 正如您在下面的代码中看到的,我使用LinkedHashMap 来访问所需的值First、Middle 和Last。

我的问题是我的NameList 标签包含多个Person 标签,而LinkedHashMap 到目前为止只给了我最后一个Person,在我的示例中(输出):

given: Ghi family: Tom given: Jkl family: Mary

如何使用LinkedHashMap 的方法访问其他两个(Karl Abc、Thomas Def)?

这是我的XML 文件:

<Sources>
<Source>
    <Year>2019</Year>
</Source>
<Source>
    <Title>Blablabla</Title>
    <Author>
        <BookAuthor>
            <NameList>
                <Person>
                    <Last>Karl</Last>
                    <First>Abc</First>
                </Person>
                <Person>
                    <Last>Thomas</Last>
                    <First>Def</First>
                </Person>
                <Person>
                    <Last>Tom</Last>
                    <First>Ghi</First>
                </Person>
            </NameList>
        </BookAuthor>
    </Author>
</Source>
<Source>
    <Author>
        <Editor>
            <NameList>
                <Person>
                    <Last>Mary</Last>
                    <First>Jkl</First>
                </Person>
            </NameList>
        </Editor>
    </Author>
</Source>

这是我的代码:

private static void XmlFileParser() throws IOException {

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

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

    try {

        Object[] deserializedData = mapper.readValue(xmlFile, Object[].class);

        for (Object element : deserializedData) {

            if (element instanceof LinkedHashMap) {
                LinkedHashMap<String, Object> el = (LinkedHashMap<String, Object>) element;

                if ((el.get("Author")) == null) {
                    continue;
                } else {

                    // Last -> family
                    // First, Middle -> given

                    if (((LinkedHashMap) el.get("Author")).get("Author") instanceof LinkedHashMap && ((((LinkedHashMap) ((LinkedHashMap) el
                            .get("Author")).get("Author")).get("NameList")) != null)) {
                        Object first = ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) el.get(
                                "Author")).get("Author")).get("NameList")).get("Person")).get("First");
                        Object middle = ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) el.get(
                                "Author")).get("Author")).get("NameList")).get("Person")).get("Middle");
                        if (first != null || middle != null) {
                            System.out.println("given: " + evaluateGiven(first, middle));
                        }

                        Object family = ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) el.get(
                                "Author")).get("Author")).get("NameList")).get("Person")).get("Last");
                        System.out.println("family: " + family);
                    } else if (((LinkedHashMap) el.get("Author")).get("Editor") instanceof LinkedHashMap && ((((LinkedHashMap) ((LinkedHashMap) el
                            .get("Author")).get("Editor")).get("NameList")) != null)) {
                        Object first = ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) el.get(
                                "Author")).get("Editor")).get("NameList")).get("Person")).get("First");
                        Object middle = ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) el.get(
                                "Author")).get("Editor")).get("NameList")).get("Person")).get("Middle");
                        if (first != null || middle != null) {
                            System.out.println("given: " + evaluateGiven(first, middle));
                        }

                        Object family = ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) ((LinkedHashMap) el.get(
                                "Author")).get("Editor")).get("NameList")).get("Person")).get("Last");
                        System.out.println("family: " + family);
                    } 
                }
            }
        }

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

我的助手类:

private static String evaluateGiven(Object first, Object middle) {
    if (first == null) {
        first = "";
    } else if (middle == null) {
        middle = "";
    }
    return first.toString() + " " + middle.toString();
}

由于我的代码很炸,你知道如何让它更小吗?

如果能得到一些帮助,我会很高兴的。

谢谢!

【问题讨论】:

  • 既然你使用jackson xml,为什么不把xml转换成一个自定义对象,由具有给定属性的类表示呢?
  • 如果您的目标是将 XML 转换为 POJO,请使用 JAXB API,它会小心地将 XML 转换为 Java 或 Java 转换为 XML。
  • 你最近问了一个类似的问题:How to deserealize multiple nested elements in Jackson?。为什么使用LinkedHashMap?您可以使用上一个问题的解决方案或创建POJO 并反序列化给定XML。
  • @MichałZiober 我被困在挑战中,只能在标签中获取多个Person标签中的最后一个Person标签(就像标签NameList中的许多Persons一样。所以我决定尝试使用LinkedHashMap 的新方法。您对如何获取所有Person 标签有什么建议吗?

标签: java xml parsing jackson linkedhashmap


【解决方案1】:

通常列表不容易处理,当我们不使用POJO 结构时,我们需要编写自定义反序列化器,它将使用Streaming API 来读取内部列表对象。您可以在下面找到简单的 POJO 模型,该模型带有 Author 类的自定义反序列化器:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

public class XmlMapperApp {

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

        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.setDefaultUseWrapper(false);
        xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);

        Source[] sources = xmlMapper.readValue(xmlFile, Source[].class);
        Stream.of(sources)
                .filter(s -> Objects.nonNull(s.getAuthor()))
                .map(s -> s.getAuthor().getPersons())
                .filter(a -> !a.isEmpty())
                .forEach(System.out::println);
    }
}

class AuthorJsonDeserializer extends JsonDeserializer<Author> {
    @Override
    public Author deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        p.nextToken(); // Skip START_OBJECT
        Author author = new Author();
        author.setType(p.getText());
        author.setPersons(new ArrayList<>());

        JsonToken token;
        while ((token = p.currentToken()) != JsonToken.END_OBJECT) {
            if (token == JsonToken.FIELD_NAME) {
                String name = p.getText();
                if ("Person".equals(name)) {
                    p.nextToken();
                    author.getPersons().add(p.readValueAs(Person.class));
                }
            }
            p.nextToken();
        }
        p.nextToken(); // Skip END_OBJECT
        p.nextToken(); // Skip END_OBJECT

        return author;
    }
}

class Source {

    private int year;
    private String title;
    private Author author;

    // getters, setters, toString
}

@JsonDeserialize(using = AuthorJsonDeserializer.class)
class Author {

    private String type;
    private List<Person> persons;

    // getters, setters, toString
}

class Person {

    private String last;
    private String first;

    // getters, setters, toString
}

上面的代码打印:

[Person{last='Karl', first='Abc'}, Person{last='Thomas', first='Def'}, Person{last='Tom', first='Ghi'}]
[Person{last='Mary', first='Jkl'}]

您可以打印整个 Source 实例:Stream.of(sources).forEach(System.out::println);,您应该会看到:

Source{year=2019, title='null', author=null}
Source{year=0, title='Blablabla', author=Author{type='BookAuthor', persons=[Person{last='Karl', first='Abc'}, Person{last='Thomas', first='Def'}, Person{last='Tom', first='Ghi'}]}}
Source{year=0, title='null', author=Author{type='Editor', persons=[Person{last='Mary', first='Jkl'}]}}

另见:how to ignore outer wrappers when parsing?

【讨论】:

    猜你喜欢
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多