如何使用LinkedHashMap解析包含多个标签的xml文件? [英] How to parse xml file containing multiple tags using LinkedHashMap?

查看:149
本文介绍了如何使用LinkedHashMap解析包含多个标签的xml文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想构建一个解析器来解析Java中的XML文件. 如下面的代码所示,我正在使用LinkedHashMap访问所需的值FirstMiddleLast.

我的问题是我有包含多个Person标签的NameList标签,而在我的示例(输出)中,到目前为止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();
}

由于我的代码非常繁琐,因此您知道如何将其缩小吗?

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

谢谢!

解决方案

通常,列表不容易处理,当我们不使用POJO结构时,我们需要编写将使用

上面的代码显示:

[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'}]}}

另请参见:如何在何时忽略外部包装器解析?

I want to build a parser to parse an XML file in Java. As you can see in my code below I am using a LinkedHashMap to access the desired values First, Middle and Last.

My problem is that I have NameList tags containing multiple Person tags and the LinkedHashMap so far gives me only the last Person, in my example (output):

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

How can I access the other two (Karl Abc, Thomas Def) using my approach with LinkedHashMap?

This is my XML file:

<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>

This is my code:

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();
    }
}

My helper class:

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

Since my code is very blown up, do you know how to make it smaller?

I would be very happy about some help.

Thank you!

解决方案

Generally lists are not handled easily and when we do not use POJO structure we need to write custom deserialiser which will use Streaming API to read inner list objects. Below you can find simple POJO model with custom deserialiser for Author class:

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
}

Above code prints:

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

You can print whole Source instance: Stream.of(sources).forEach(System.out::println); and you should see:

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'}]}}

See also: how to ignore outer wrappers when parsing?

这篇关于如何使用LinkedHashMap解析包含多个标签的xml文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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