Что такое XML?
Аббревиатура "XML" означает - е X tensible M arkup L anguage. Он имеет структуру разметки, аналогичную HTML, и был разработан для хранения и передачи данных. Он определяет набор правил, которые делают его читаемым как человеком, так и машиной.
Несмотря на то, что XML является языком разметки, таким как HTML, он обычно используется для обмена данными между веб-службами, серверными приложениями и интерфейсами, как и JSON, и считается его предшественником.
Если вам интересно читать о чтении и записи JSON на Java , мы уже рассмотрели это!
Важно отметить, что XML не имеет предопределенного набора тегов, таких как HTML, а скорее определяется пользователем. Именно эта гибкость привела к созданию множества форматов документов, таких как RSS , Atom , SOAP и XHTML . По сути, все эти форматы являются подмножествами XML.
Давайте посмотрим на простой XML-документ, который реплицирует тот же объект, который мы использовали ранее в отношении JSON:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<age>31</age>
<hobbies>
<element>Football</element>
<element>Swimming</element>
</hobbies>
<isMarried>true</isMarried>
<kids>
<person>
<age>5</age>
<name>Billy</name>
</person>
<person>
<age>3</age>
<name>Milly</name>
</person>
</kids>
<name>Benjamin Watson</name>
</person>
Ключевое различие между XML и JSON заключается в том, что мы определяем
этот файл с версией XML и кодируем в начале документа с помощью <?xml>
. Еще одно отличие состоит в том, что каждое свойство объекта должно
быть заключено в отдельный тег - <age>31</age>
. Элементы массива не
могут быть указаны без тега, поэтому, чтобы перечислить их, мы помещаем
их в <element>...</element>
внутри <hobbies>...</hobbies>
.
JAXB
Поскольку XML - это текстовый формат, вы можете использовать те же методы для его чтения и записи, что и для любого другого текстового файла.
Java, однако, обеспечивает удобный способ манипулирования XML с использованием структуры под названием J AVA rchitecture для X ML B inding или JAXB для краткости. Это позволяет нам отображать объект Java в документы XML и наоборот. JAXB был впервые представлен в JDK 1.6 и недоступен в предыдущих версиях.
Поскольку JAXB является стандартной структурой JDK, нет необходимости включать в проект какие-либо внешние зависимости для JDK 1.6+.
Примечание. Если вы используете Java 9 или выше, вам следует
включить в команду javac
дополнительный параметр. Если вы используете
IDE, например IntelliJ IDEA или Eclipse, поищите дополнительную
настройку параметров компилятора и убедитесь, что она включает
--add-modules java.xml.bind
.
В случае IntelliJ IDEA он находится в Preferences
->
Build, Execution, Deployment
-> Compiler
-> Java Compiler
.
Если вы все равно будете получать такие ошибки, как
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBContext
даже после добавления дополнительной опции компилятора, добавьте
следующие зависимости Maven:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
Концепции ядра JAXB называются
сортировочные
и демаршалинг .
Неудивительно, что они представлены классами Marshaller
и
Unmarshaller
.
Маршаллинг - это процесс преобразования объектов Java в XML, а демаршаллинг - это процесс преобразования XML в объекты Java.
JAXB настраивается с использованием аннотаций, которые импортируются из
пакета javax.xml.bind.annotations
Давайте определим класс Java, который представляет человека, описанного в нашем XML-документе:
@XmlRootElement
public class Person {
public Person(String name, int age, boolean isMarried, List<String> hobbies, List<Person> kids) {
this.name = name;
this.age = age;
this.isMarried = isMarried;
this.hobbies = hobbies;
this.kids = kids;
}
public Person(String name, int age) {
this(name, age, false, null, null);
}
private String name;
private Integer age;
private Boolean isMarried;
private List<String> hobbies;
private List<Person> kids;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isMarried() {
return isMarried;
}
@XmlElement(name = "isMarried")
public void setMarried(boolean married) {
isMarried = married;
}
@XmlElementWrapper(name = "hobbies")
@XmlElement(name = "element")
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public List<Person> getKids() {
return kids;
}
@XmlElementWrapper(name = "kids")
@XmlElement(name = "person")
public void setKids(List<Person> kids) {
this.kids = kids;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", isMarried=" + isMarried +
", hobbies=" + hobbies +
", kids=" + kids +
'}';
}
}
@XmlRootElement
- сопоставляет класс или тип перечисления с элементом
XML. Он описывает корневой элемент XML-документа и должен быть указан в
объявлении класса Person
@XmlElementWrapper
- генерирует элемент-оболочку вокруг
XML-представления, в нашем случае List
Элементы списка следует
указывать явно с @XMLElement
аннотации @XMLElement.
@XMLElement
- сопоставляет свойство объекта Java с элементом XML,
производным от имени свойства. Чтобы указать другое имя свойства XML, мы
включаем его как параметр String в объявление аннотации, то есть
(name = "person")
.
Демаршаллинг
Простейший пример техники маршалинга потребует от нас создать
JAXBContext
, передав Person.class
в качестве единственного входного
параметра его конструктора.
Затем создается createUnmarshaller()
, а экземпляр фактического
Person
создается его методом unmarshal()
.
Обязательно используйте явное приведение типов, так как unmarshal
метод возвращает тип Object:
public class Solution {
public static void main(String[] args) throws Exception {
Person person = XMLtoPersonExample("person.xml");
System.out.println(person);
}
private static Person XMLtoPersonExample(String filename) throws Exception {
File file = new File(filename);
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return (Person) jaxbUnmarshaller.unmarshal(file);
}
}
После запуска этого кода вы должны увидеть что-то вроде:
Person{name='Benjamin Watson', age=31, isMarried=true, hobbies=[Football, Swimming], kids=[Person{name='Billy', age=5, isMarried=null, hobbies=null, kids=null}, Person{name='Milly', age=3, isMarried=null, hobbies=null, kids=null}]}
Маршаллинг
Чтобы продемонстрировать способность JAXB записывать XML-файл с использованием объекта Java в качестве источника, мы добавим следующий метод:
private static void personToXMLExample(String filename, Person person) throws Exception {
File file = new File(filename);
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(person, file);
jaxbMarshaller.marshal(person, System.out);
}
Он очень похож на предыдущий пример и включает повторное JAXBContext
Однако на этот раз процесс пойдет в обратном направлении, и вывод XML
будет записан в файл и консоль.
Добавив вызов этого метода в качестве последней строки в
Solution.main()
например:
personToXMLExample("person-output.xml", person);
и запустив его, мы получим досадное исключение.
Exception in thread "main" java.lang.NullPointerException
at com.stackabuse.xml.Person.isMarried(Person.java:49)
at com.stackabuse.xml.Person$JaxbAccessorM_isMarried_setMarried_boolean.get(MethodAccessor_Boolean.java:61)
...
Мы допустили ошибку, установив isMarried
поля isMarried в
класс-оболочку Boolean
а тип возвращаемого значения getter
isMarried()
в примитивное boolean
, что приводит к тому, что JAXB
пытается распаковать null
и в результате выбрасывает
NullPointerException
.
Быстрое и простое решение этой проблемы - выровнять эти два значения
либо с boolean
Boolean
.
После устранения проблемы мы получим следующий вывод как в консоль, так и в файл:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<age>31</age>
<hobbies>
<element>Football</element>
<element>Swimming</element>
</hobbies>
<kids>
<person>
<age>5</age>
<name>Billy</name>
</person>
<person>
<age>3</age>
<name>Milly</name>
</person>
</kids>
<isMarried>true</isMarried>
<name>Benjamin Watson</name>
</person>
Как мы видим, он полностью идентичен исходному XML-файлу, который мы
упорядочили в объект person
Заключение
Чтение и запись XML на Java можно легко выполнить с помощью инфраструктуры JAXB. Используя аннотации, мы определяем правила отображения между Java-классами и XML-документами, которые представляют их объекты.
XML часто считается устаревшим форматом, который уступает JSON. Однако знание того, как его читать и писать с помощью Java, является полезным навыком для любого разработчика программного обеспечения, поскольку многие службы в Интернете все еще используют его и еще не имеют JSON API. Это также относится ко многим форматам файлов, в которых данные хранятся в файлах в формате XML.
Хотя, если вам больше нравится JSON, я бы посоветовал прочитать о чтении и записи JSON на Java, мы это тоже рассмотрели!