Teisendage JSON XML-iks Java kasutades Gsoni ja JAXB-d

⚡ Nutikas kokkuvõte

Teisendage JSON XML-iks Java Gsoni ja JAXB abil kaardi abilping mõlemad vormingud samale annoteeritud Java klassid. See artikkel defineerib iga vormingu, seadistab projekti, eraldab XML-i JAXB abil, kirjutab JSON-i Gsoniga ja pöörab kogu protsessi ümber.

  • 🗝️ JSON-i struktuur: Andmed salvestatakse võtme ja väärtuse paaridena looksulgudes, iga kirje eraldades komadega.
  • ???? ️ XML-struktuur: Andmeid salvestatakse pesastatud sõlmedesse, kus iga avamissildi jaoks on vaja vastavat sulgemissilti.
  • 🔗 Jagatud mudel: Üks komplekt annoteeritud Java Klassid toimivad sillana, seega kumbagi vormingut ei parsita otse teiseks.
  • 📥 Lahtiühendamine: JAXB loeb XML-faili ja tagastab asustatud arvu. Java objektipuu Unmarshaller klassi kaudu.
  • 📤 Voogedastuse kirjutamine: Gson JsonWriter väljastab JSON-i inkrementaalselt beginObject, name, value ja endObject kutsetega.
  • 🔄 Reverse Tee: JsonReader ehitab objektid JSON-ist uuesti üles ja JAXB Marshaller kirjutab need XML-ina tagasi välja.
  • ⚠️ Käitusaja märkus: JAXB lahkus JDK-st kell Java 11, seega tuleb jakarta.xml.bind sõltuvus selgesõnaliselt lisada.

Teisenda JSON XML-iks Java

Mis on JSON?

JSON on lühend sõnadest JavaSkriptiobjekti tähistus (Script Object Notation), mis on andmevorming, mis järgib reegleid, mida enamik programmeerimiskeeli lugeda oskab. Saame selle hõlpsalt faili salvestada või andmebaasi talletada. JSON-vorming kasutab andmete kirjeldamiseks võtme-väärtuse paare.

Järgmises näites defineerime JSON-stringi, mis salvestab isikuandmeid:

{
"username" : "guru99user",
"email" : "guru99user@mail.com"
}

Seega on JSON-i süntaks väga lihtne. Igal andmeüksusel on kaks osa, võti ja väärtus, mis vastavad kirje väljanimele ja selle väärtusele. Lähemalt vaadates on mõned reeglid, näiteks see:

  • JSON-string on ümbritsetud lokkis sulgudega {}.
  • JSON-võtmed peavad olema jutumärkides ja stringväärtused tuleb samuti jutumärkides esitada.
  • Kui andmeid on rohkem (rohkem võtme => väärtuse paare), eraldame need komadega (,).
  • JSON-võtmed peaksid kasutama lihttähti, numbreid või alakriipsu, ilma tühikuteta ja esimene märk ei tohiks olla number.

Mis on XML?

XML tähistab laiendatavat märgistuskeelt (eXtensible Markup Language), mille pakkus välja World Wide Web Consortium (https://www.w3.org/) teiste märgistuskeelte loomiseks. See on lihtne alamhulk, mis suudab kirjeldada paljusid erinevat tüüpi andmeid, seega on see väga kasulik andmete jagamiseks süsteemide vahel.

XML-i sildid pole sageli eelmääratletud, vaid need luuakse vastavalt kasutaja tavadele. XML tutvustab uusi funktsioone, mis põhinevad HTML-i eelistel.

Erinevatele süsteemidele ja lahendustele on saadaval mõned kasulikud XML-funktsioonid:

  • XML on laiendatav: XML võimaldab teil luua oma kohandatud silte, mis sobivad teie rakendusega.
  • XML kannab andmeid, see ei kuva neid: XML võimaldab teil andmeid salvestada olenemata sellest, kuidas neid kuvatakse.
  • XML on levinud standard: XML-i töötas välja World Wide Web Consortium (W3C) ja see on saadaval avatud standardina.

XML on üles ehitatud pesastatud sõlmestruktuurile. Igal sõlmel on avav ja sulgev märgend järgmiselt:

<node>content</node>

Milles:

  • on avatud silt ja selle sildi nime määrasite teie.
  • on sulgev silt ja selle sildi nimi peab ühtima avava sildi nimega.
  • sisu on selle sildi sisu.

Iga XML-faili ülaosas tuleb deklareerida silt, mis näitab kasutatavat XML-versiooni. Juhisildi süntaks on järgmine:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

JSON vs XML: peamised erinevused

Mõlemad vormingud kannavad struktureeritud andmeid ja allolev tabel näitab, miks projektil võib olla vaja nende vahel liikuda.

Parameeter JSON XML
Süntaksi stiil Võtme ja väärtuse paarid Pesastatud sildid
Andmetüübid String, arv, tõeväärtus, null, massiiv, objekt Ainult tekst, tüübid pärinevad skeemist
Näitajad Ei toetata Toetatud mis tahes elemendi puhul
Kommentaarid Ei toetata Toetatud
Paljusõnalisus kompaktne Rohkem sõnastavat, sest sildid korduvad
Skeemi valideerimine JSON-skeem, valikuline DTD ja XSD, küps
Tüüpiline kasutamine Veebi API-d ja konfiguratsioon Ettevõtte sõnumside ja dokumendid

Mis on Gson?

Gson (https://github.com/google/gson) On Java teeki, mis võimaldab kasutajatel teisendada Java objekti JSON-stringiks ja ka JSON-stringi tagasi teisendamiseks Java objektiks. Gson saab töötada meelevaldselt Java objektid, sealhulgas olemasolevad objektid, mille lähtekoodi sul pole.

Alates versioonist 1.6 tutvustab Gson kahte klassi, JsonReader ja jsonWriter, et pakkuda JSON-andmete voogedastustöötlust.

  • jsonWriter – JSON-i voogedastus. Me loome jsonWriter objekt. JSON-objekti loomise alustamiseks ja lõpetamiseks kasutame funktsioone beginObject() ja endObject()Nende kahe päringu vahel kirjutame andmed paaridena (võti => väärtus).
JsonWriter writer = new JsonWriter();
writer.beginObject();
writer.name("key").value("value");
writer.endObject();
  • JsonReader – JSON-ist lugemine voogesituse teel. Loome JsonReaderi objekti. JSON-objekti lugemise alustamiseks ja lõpetamiseks kasutame funktsioone beginObject() ja endObject(). Nende kahe käsu vahel loeme andmeid paaridena (võti => väärtus).
JsonReader reader = new JsonReader();
reader.beginObject();
while (reader.hasNext()) {
	String name = reader.nextName();
	if (name.equals("key")) {
		String value = reader.nextString();
	}
}
reader.endObject();

Gson-i voogesituse töötlemine on kiire. Siiski peate iga JSON-andmete paari (võti => väärtus) ise käsitlema.

Mis on JAXB?

JAXB tähistab Java ArchiTecture XML Binding jaoks, mis on teek, mis kasutab teisendamiseks annotatsioone Java objektidelt XML-sisule ja vastupidi. Kuna JAXB on defineeritud spetsifikatsiooniga, saame kasutada selle standardi erinevaid rakendusi.

JAXB-ga kasutame sageli järgmisi põhilisi annotatsioone:

  • @XmlRootElement: See annotatsioon määrab XML-faili kõige välimise sildi ja seetõttu deklareeritakse see klassi kohal.
  • @XmlElementWrapper: see märkus loob kogude ümber ümbrise XML-elemendi.
  • @XmlElement: See märkus deklareerib, et objekti omadusest saab XML-faili alammärgend.
  • @XmlAttribute: See annotatsioon deklareerib, et objekti omadusest saab ümbritseva sildi atribuut.

Üldine teostus on järgmine. Esmalt initsialiseerime JAXBContekst objektiga MinuObject klass teisendamiseks.

JAXBContext jaxbContext = JAXBContext.newInstance(MyObject.class);

see JAXBContekst objektil on meetod, mis loob objekti, mis teisendab XML-sisu Java objekt, see Unmarshaller.

Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

Sama JAXBContekst objektil on ka meetod, mis loob objekti, mis teisendab a Java objekt XML-sisuks, Marshaller.

Marshaller marshallerObj = jaxbContext.createMarshaller();

⚠️ Hoiatus: JAXB eemaldati JDK-st aastal Java 11. sisse Java 11 ja uuemate versioonide puhul lisage API ja käitusaja implementatsioon projektile selgesõnaliselt, näiteks jakarta.xml.bind:jakarta.xml.bind-api Koos org.glassfish.jaxb:jaxb-runtimeja importige märkused saidilt jakarta.xml.bind.annotation asemel javax.xml.bind.annotation.

Kuidas teisendada XML-i JSON-iks?

Rakendame XML-i JSON-iks teisendamise näite järgmisel platvormil. Allpool olevad versioonid on need, mida kasutati ekraanipiltide jaoks. JDK uuemad versioonid, Eclipseja Gson toimivad samamoodi, arvestades ülaltoodud JAXB märkust.

  • OpenJDK 8 jaoks Ubuntu 18.04 x64.
  • Eclipse IDE 2019-03 (4.11.0) x64 Java Arendamine Ubuntu.
  • Gson 2.8.5.

Step 1) Loo projekt.
Loo uus Java projekti.

Loo uus Java Projekt.

Step 2) Määrake projekti nimi.
Määrake projekti nimeks XmlToJsonExample.

Määrake projekti nimi

Step 3) Looge kaust.
Loo kaust andmed/sisend mis sisaldab kahte faili sample.xml ja sample.json.

Loo kausta andmed

Defineerime kõigepealt oma XML-i järgmiselt: osakond, rollja inimene omadused.

Üldine arhitektuur on järgmine: ühel osakonnal on palju rolle ja ühel rollil on palju isikuid. Allolev diagramm näitab neid seoseid.

Objektide suhted

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
	<department>
		<roles>
			<role id="1">
				<position>head</position>
				<salary>10k</salary>
			</role>
			<role id="2">
				<position>manager</position>
				<salary>8k</salary>
			</role>
			<role id="3">
				<position>employee</position>
				<salary>5k</salary>
			</role>
		</roles>
		<persons>
			<person id="1">
				<name>Red</name>
				<role>1</role>
			</person>
			<person id="2">
				<name>Green</name>
				<role>2</role>
			</person>
			<person id="3">
				<name>Blue</name>
				<role>2</role>
			</person>
			<person id="4">
				<name>Yellow</name>
				<role>3</role>
			</person>
			<person id="5">
				<name>Brown</name>
				<role>3</role>
			</person>
		</persons>
	</department>
</root>

Teiseks defineerime sama ideed väljendava JSON-i. Pane tähele, et lamedast isikute loendist saab iga rolli sees pesastatud massiiv, mis on täpselt see teisendus, mida teisenduskood teeb.

{
	"roles": [
		{
			"id": "1",
			"position": "head",
			"salary": "10k",
			"persons": [
				{
					"id": "1",
					"name": "Red"
				}
			]
		},
		{
			"id": "2",
			"position": "manager",
			"salary": "8k",
			"persons": [
				{
					"id": "2",
					"name": "Green"
				},
				{
					"id": "3",
					"name": "Blue"
				}
			]
		},
		{
			"id": "3",
			"position": "employee",
			"salary": "5k",
			"persons": [
				{
					"id": "4",
					"name": "Yellow"
				},
				{
					"id": "5",
					"name": "Brown"
				}
			]
		}
	]
}

Step 4) Defineeri objektid.
Määrake paketis vastavad objektiklassid mudel.

Määratlege objektiklassid

Roll.java

@XmlRootElement(name = "role")
public class Role {
	private String id;
	private String position;
	private String salary;
	public Role() {
		super();
	}
	public Role(String id, String position, String salary) {
		super();
		this.id = id;
		this.position = position;
		this.salary = salary;
	}
	@XmlAttribute(name = "id")
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	@XmlElement(name = "position")
	public String getPosition() {
		return position;
	}
	public void setPosition(String position) {
		this.position = position;
	}
	@XmlElement(name = "salary")
	public String getSalary() {
		return salary;
	}
	public void setSalary(String salary) {
		this.salary = salary;
	}
}

Person.java

@XmlRootElement(name = "person")
public class Person {
	private String id;
	private String name;
	private String role;
	public Person() {
		super();
	}
	public Person(String id, String name, String role) {
		super();
		this.id = id;
		this.name = name;
		this.role = role;
	}
	@XmlAttribute(name = "id")
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	@XmlElement(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	@XmlElement(name = "role")
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
}

Osakond.java

@XmlRootElement(name = "department")
public class Department {
	private List<Role> roles;
	private List<Person> persons;
	public Department() {
		super();
	}
	public Department(List<Role> roles, List<Person> persons) {
		super();
		this.roles = roles;
		this.persons = persons;
	}
	@XmlElementWrapper(name = "roles")
	@XmlElement(name = "role")
	public List<Role> getRoles() {
		return roles;
	}
	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}
	@XmlElementWrapper(name = "persons")
	@XmlElement(name = "person")
	public List<Person> getPersons() {
		return persons;
	}
	public void setPersons(List<Person> persons) {
		this.persons = persons;
	}
}

XMLModel.java

@XmlRootElement(name = "root")
public class XMLModel {

	private Department department;

	public XMLModel() {
		super();
	}

	public XMLModel(Department department) {
		super();
		this.department = department;
	}

	@XmlElement(name = "department")
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

}

Step 5) Seadke raamatukogu üles.
Lisage ja seadistage Gson 2.8.5 teek Java Ehitage rada.

Seadistage raamatukogu Gson

Lisage teeki Gson 2.8.5 Java Ehitage rada

Kui projekt kasutab Maven Käsitsi lisatud jar-faili asemel deklareeritakse samad teegid sõltuvustena. Versioon 2.8.5 on siia kinnitatud, et see sobiks ekraanipiltidega, ja kõik hilisemad Gson-i versioonid töötavad selle näite puhul identselt:

<dependencies>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
    </dependency>

    <!-- required on Java 11 and later -->
    <dependency>
        <groupId>jakarta.xml.bind</groupId>
        <artifactId>jakarta.xml.bind-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
    </dependency>
</dependencies>

Teisendage XML-sõnum järgmiseks Java objektid JAXB abil

Esiteks defineerime paketis toimivad klassid teenus.

Määratlege esinemisklassid

Esimese protsessi esimeses etapis kasutame JAXB-i sorteerimiseta tehnikat.

Marshallimise lõpetamine annab kliendirakendusele võimaluse teisendada XML-andmeid JAXB-st tuletatud andmeteks. Java objektid.

Me defineerime funktsiooni getObjectFromXmlFile et meie XML-fail uuesti marsruudilt eemaldada Java objekt. See funktsioon on defineeritud klassis XMLService.

public XMLModel getObjectFromXmlFile(String filePath) {
	try {
		File file = new File(filePath);
		JAXBContext jaxbContext = JAXBContext.newInstance(XMLModel.class);

		Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
		XMLModel root = (XMLModel) jaxbUnmarshaller.unmarshal(file);

		return root;
	} catch (JAXBException e) {
		e.printStackTrace();
		return null;
	}
}

Kutsume klassis ülaltoodud koodi XmlToJsonService.

XMLService xmlService = new XMLService();
XMLModel xmlModel = xmlService.getObjectFromXmlFile(filePathIn);

Department department = xmlModel.getDepartment();
List<Role> roles = department.getRoles();
List<Person> persons = department.getPersons();

Selleks hetkeks on XML-failist saanud kolm Java mälus olevad objektid. Järgmine samm kirjutab need JSON-vormingusse.

Muutma Java objektid Gsoni abil JSON-sõnumile

Selles etapis defineerime funktsiooni writeDataToJsonFile andmete kirjutamiseks JSON-faili. See funktsioon on defineeritud klassis JsonService.

Pane tähele, et JSON-objektide loendi kirjutamiseks kasutame funktsioone beginArray() ja endArray()Nende kahe kutse vahel kirjutame iga JSON-objekti.

public void writeDataToJsonFile(String filePath, List<Role> roles, List<Person> persons) {
	try {
		JsonWriter writer = new JsonWriter(new FileWriter(filePath));
		writer.setIndent("    ");
		writer.beginObject();
		writer.name("roles");
		writer.beginArray();
		for (Role role : roles) {
			writer.beginObject();
			writer.name("id").value(role.getId());
			writer.name("position").value(role.getPosition());
			writer.name("salary").value(role.getSalary());
			writer.name("persons");
			writer.beginArray();
			for (Person person : persons) {
				if (person.getRole().equalsIgnoreCase(role.getId())) {
					writer.beginObject();
					writer.name("id").value(person.getId());
					writer.name("name").value(person.getName());
					writer.endObject();
				}
			}
			writer.endArray();
			writer.endObject();
		}
		writer.endArray();
		writer.endObject();
		writer.close();
	} catch (IOException e) {
	}
}

Kutsume klassis ülaltoodud koodi XmlToJsonService.

JsonService jsonService = new JsonService();
jsonService.writeDataToJsonFile(filePathOut, roles, persons);

See on esimene protsess. Sisemine tsükkel sobitab iga inimese praeguse rolli ID-ga, nii muutubki lame XML-isikute loend pesastatud JSON-massiiviks.

Teisenda JSON-sõnum järgmiseks Java objektid Gsoni abil

Teise protsessi esimesel sammul defineerime funktsiooni hankigeDataFromJsonFile JSON-failist andmete lugemiseks. See funktsioon on defineeritud klassis JsonService.

Pane tähele, et JSON-objektide loendi lugemiseks kasutame funktsioone beginArray() ja endArray()Nende kahe kutse vahel loeme iga JSON-objekti.

public void getDataFromJsonFile(String filePath, List<Role> roles, List<Person> persons) {
	try {
		JsonReader reader = new JsonReader(new FileReader(filePath));
		reader.beginObject();
		while (reader.hasNext()) {
			String nameRoot = reader.nextName();
			if (nameRoot.equals("roles")) {
				reader.beginArray();
				while (reader.hasNext()) {
					reader.beginObject();
					Role role = new Role();
					while (reader.hasNext()) {
						String nameRole = reader.nextName();
						if (nameRole.equals("id")) {
							role.setId(reader.nextString());
						} else if (nameRole.equals("position")) {
							role.setPosition(reader.nextString());
						} else if (nameRole.equals("salary")) {
							role.setSalary(reader.nextString());
						} else if (nameRole.equals("persons")) {
							reader.beginArray();
							while (reader.hasNext()) {
								reader.beginObject();

								Person person = new Person();
								person.setRole(role.getId());

								while (reader.hasNext()) {
									String namePerson = reader.nextName();
									if (namePerson.equals("id")) {
										person.setId(reader.nextString());
									} else if (namePerson.equals("name")) {
										person.setName(reader.nextString());
									}
								}
								persons.add(person);
								reader.endObject();
							}
							reader.endArray();
						}
					}
					roles.add(role);
					reader.endObject();
				}
				reader.endArray();
			}
		}
		reader.endObject();
		reader.close();
	} catch (IOException e) {

	}
}

Kutsume klassis ülaltoodud koodi XmlToJsonService.

JsonService jsonService = new JsonService();
List<Role> roles = new ArrayList<>();
List<Person> persons = new ArrayList<>();

jsonService.getDataFromJsonFile(filePathIn, roles, persons);

Muutma Java objektid XML-sõnumisse JAXB abil

Selles etapis kasutame JAXB sorteerimistehnikat.

Marshalling annab kliendirakendusele võimaluse teisendada JAXB-st tuletatud Java objektipuu XML-andmeteks.

Me defineerime funktsiooni parseObjectToXml marsruutima Java XML-sõnumi objekti. See funktsioon on defineeritud klassis XMLService.

public void parseObjectToXml(String filePath, XMLModel xmlModel) {
	try {
		JAXBContext contextObj = JAXBContext.newInstance(XMLModel.class);

		Marshaller marshallerObj = contextObj.createMarshaller();
		marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

		marshallerObj.marshal(xmlModel, new FileOutputStream(filePath));
	} catch (JAXBException je) {
		System.out.println("JAXBException");
	} catch (IOException ie) {
		System.out.println("IOException");
	}
}

Kutsume klassis ülaltoodud koodi XmlToJsonService.

XMLService xmlService = new XMLService();
XMLModel xmlModel = new XMLModel();

Department department = new Department();
department.setRoles(roles);
department.setPersons(persons);

xmlModel.setDepartment(department);

xmlService.parseObjectToXml(filePathOut, xmlModel);

See on teine ​​protsess. Genereeritud fail vastab algsele sample.xml-failile, mis kinnitab, et edasi-tagasi reis säilitas kõik väärtused.

Kuidas teisendada JSON-i XML-iks Java ilma modelliklassita?

Ülaltoodud lähenemisviis on õige valik, kui struktuur on teada ja stabiilne, sest annoteeritud klassid dokumenteerivad vastuolu.tract. Kui struktuur on tundmatu või muutub sageli, on üldine konverter kiirem.

. org.json teek teostab teisenduse kahel real, ilma ühegi mudeliklassita:

import org.json.JSONObject;
import org.json.XML;

public class QuickConverter {

    public static void main(String[] args) {
        String str = "{\"username\":\"guru99user\",\"email\":\"guru99user@mail.com\"}";

        JSONObject json = new JSONObject(str);
        String xml = XML.toString(json);

        System.out.println(xml);
    }
}

Väljund:

<username>guru99user</username><email>guru99user@mail.com</email>

Pane tähele, et üldine marsruut ei tooda juurelementi ega atribuute, seega XML.toString(json, "root") on tavaliselt nõutav. Allolev tabel esitab need kaks lähenemisviisi kõrvuti.

Kriteerium Gson koos JAXB-ga org.json üldine konversioon
Nõutavad mudeliklassid Jah Ei
Kontroll struktuuri üle Täielik, sh atribuudid Piiratud, ainult elemendid
Reshaping andmed Võimalik, nagu on näidatud pesastatud isikutega Pole võimalik
Koodiread Palju Kaks
Parim on Stabiilsed, dokumenteeritud skeemid Juhuslikud või tundmatud struktuurid

JAXB loeb XML-andmeid ja Gson kirjutab need JSON-i ning vastupidine tee kasutab lugemiseks Gsoni JSON andmeid, samal ajal kui JAXB need XML-i tagasi kirjutab. Lisateabe saamiseks vaadake üle XML põhialused, laiem Java juhendajaja Jasperi aruanded, mis kasutab mõlemat vormingut aruande andmeallikatena.

KKK

JAXB eemaldati JDK-st aastal Java 11. Lisa jakarta.xml.bind API koos käituskeskkonnaga, näiteks jaxb-runtime, ja uuenda importimist javaxist jakartasse.

Ei. Gson töötleb ainult JSON-i. XML peab esmalt muutuma Java objektid JAXB või mõne muu parseri, näiteks Jackson XML-i kaudu, enne kui Gson saab need serialiseerida.

XmlElement loob väärtust sisaldava lapsesildi, samas kui XmlAttribute paigutab väärtuse ülemsildi avasildi sisse. Atribuudid ei saa sisaldada pesastatud struktuure.

Voogedastus hoiab mälukasutuse madalal ja võimaldab väljundstruktuuril sisendklassidest erineda, mis juhtubki siis, kui isikud on siin rollide sisse pesastatud.

Jah, XML-näidisdokumendist. Kontrollige kollektsioonide ümbrise annotatsioone, sest genereeritud klassid jätavad sageli XmlElementWrapperi välja ja loovad lameda struktuuri.

JSON ja selle ridade eraldatud variant domineerivad, kuna need seostuvad otse Python sõnaraamatuid ja voogesitavad tõhusalt. XML-i kasutatakse endiselt seal, kus pärandettevõtte süsteemid pakuvad lähteandmeid.

Võta see postitus kokku järgmiselt: