如何使用LinkedHashMap解析包含多个标签的xml文件? [英] How to parse xml file containing multiple tags using LinkedHashMap?
问题描述
我想构建一个解析器来解析Java
中的XML
文件.
如下面的代码所示,我正在使用LinkedHashMap
访问所需的值First
,Middle
和Last
.
我的问题是我有包含多个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();
}
由于我的代码非常繁琐,因此您知道如何将其缩小吗?
我会很高兴获得一些帮助.
谢谢!
通常,列表不容易处理,当我们不使用 上面的代码显示: 您可以打印整个 另请参见:如何在何时忽略外部包装器解析? I want to build a parser to parse an My problem is that I have How can I access the other two (Karl Abc, Thomas Def) using my approach with This is my This is my code: My helper class: 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 Above code prints: You can print whole See also: how to ignore outer wrappers when parsing? 这篇关于如何使用LinkedHashMap解析包含多个标签的xml文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!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'}]}}
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
.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
LinkedHashMap
?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>
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
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
}
[Person{last='Karl', first='Abc'}, Person{last='Thomas', first='Def'}, Person{last='Tom', first='Ghi'}]
[Person{last='Mary', first='Jkl'}]
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'}]}}