Jednym z problemów komunikacji na linii człowiek – komputer jest sposób zapisu danych i informacji. To co jest czytelne dla komputera zwykle jest nieczytelne dla człowieka, i na odwrót. W tym artykule opowiem Ci o JSON i XML, oraz jak korzystać z nich za pomocą Pythona.
Aktualnie stosowanymi sposobami zapisu danych są JSON i XML. Obie notacje zostały wprowadzone w celu ustandaryzowania notacji danych w internecie.
JSON
JSON to obiektowy sposób notacji danych bazujący na JavaScript.
JSON charakteryzuje się tym, że jest czytelny zarówno dla maszyny, jak i człowieka.
Być może widząc kod JSONa zauważyłeś podobieństwo do słownika. Co prawda słownik dostępny w Pythonie i JSON nie są identyczne, jednak bardzo łatwo je między sobą konwertować.
Spróbujmy wczytać pokazany wyżej JSON za pomocą metody json.loads.
import json
json_text = str()
with open('json_example.json', 'r') as f:
json_text = f.read()
data = json.loads(json_text)
print(data)
# wynik: {'posts': [{'name': 'Web Scraping w Pythonie', 'url': 'http://kamil.kwapisz.pl/web-scraping-python/', 'author': 'Kamil Kwapisz'}, {'name': 'PEP 8 – czyli gramatyka dla programisty', 'url': 'http://kamil.kwapisz.pl/gramatyka-dla-programisty/', 'author': 'Kamil Kwapisz'}], 'owner': 'Kamil Kwapisz', 'website': 'kamil.kwapisz.pl', 'lang': 'polish'}
print(type(data))
# wynik: <class 'dict'>
Jeżeli jednak dane zapisane w JSONie mamy w pliku, a nie w zmiennej tekstowej możemy użyć metody json.load. (PS, tutaj poznasz jak obsługuje się pliki w Pythonie)
with open("json_example.json", "r") as file:
data = json.load(file)
W tym momencie do danych pobranych z JSONa dostajemy się metodami obsługi pythonowego słownika.
>>> data['owner']
'Kamil Kwapisz'
>>> len(data['posts'])
2
>>> data['posts'][0]
{'name': 'Web Scraping w Pythonie', 'url': 'http://kamil.kwapisz.pl/web-scraping-python/', 'author': 'Kamil Kwapisz'}
>>> data['posts'][0]['name']
'Web Scraping w Pythonie'
Oprócz wczytywania danych w JSONie do pythonowego słownika możemy działać w drugą stronę, czyli tworzyć JSONa ze słownika za pomocą metody json.dumps.
>>> data = {
'bool': True,
'none element': None
}
>>> print(json.dumps(data))
{"bool": true, "none element": null}
Na powyższym przykładzie widać dwie praktyczne różnice pomiędzy JSONem a słownikiem.
W Pythonie zmienne logiczne zapisujemy z dużych liter (True/False), a w JSONie napisane są z małej litery (true/false).
W Pythonie występuje None, a w JSONie null.
Jeżeli zapisujemy JSONa do pliku możemy użyć metody json.dump
with open('json_data.json', 'w') as json_file:
json.dump(data, json_file)
Wykorzystanie JSON
Notacja JSON jest najczęściej wykorzystywana do przesyłania danych w REST API.
Zagrożenia bezpieczeństwa
JSON jest notacją bez kontroli błędów czy ściśle narzuconego formatu. Dostawca API może zmienić format dostarczanych danych bez poinformowania programistów o zmianach.
Taka sytuacja może spowodować awarię naszego serwisu, lub co gorsze, spowoduje niezauważony błąd, który przełoży się na błędne wykonanie narażające naszą aplikację lub dane na niebezpieczeństwo.
Rozwiązaniem tego problemu może być JSON Schema, za pomocą którego jesteśmy w stanie przeprowadzić walidację JSONa.
Zalety i wady JSON
Zalety:
- łatwiejszy do parsowania
- zajmuje mniej miejsca (używanych jest mniej znaków)
- istnieje rozróżnienie między typami danych
- łatwo przedstawić wartość null
- łatwo odróżnić pojedyncze dane od list danych
- czytelność
Wady:
- podatny na błędy
- sprawia zagrożenie bezpieczeństwa
XML
XML (Extensible Markup Language) jest uniwersalnym językiem znaczników.
Przeanalizujmy kod XML zawierający identyczne dane jak JSON zamieszczony wyżej.
Pierwszą widoczną różnicą jest występowanie nagłówka. Jak widać na przykładzie nagłówek wskazuje na wersję języka XML oraz kodowanie (mega ważne w przypadku naszego języka ojczystego ;)).
Kod XML, jak sama nazwa wskazuje, jest zbudowany ze znaczników. Znaczniki muszą mieć zaznaczony początek (<author>) oraz koniec (</author>). Dane znajdują się pomiędzy początek i końcem znacznika.
Podobieństwo języka XML do HTMLa nie jest przypadkowe, bowiem HTML jest pewnym uproszczeniem XMLa. Główną różnicą w zapisie jest to, że XML zwraca uwagę na wielkość liter oraz zachowuje białe znaki.
Niestety parsowanie kodu XML w kodzie nie jest tak proste jak w przypadku JSONa.
Istnieje kilka bibliotek pozwalających parsować XML, ja jednak jestem fanem pakietu BeautifulSoup.
O tym narzędziu mogłeś już przeczytać w artykule Web scraping w Pythonie. Świetnie sprawdza się ono do parsowania zarówno kodu HTML jak i XML.
Wczytajmy więc pokazany wyżej kod XML
from bs4 import BeautifulSoup
with open('xml_example.xml', 'r', encoding='utf-8') as xml_file:
data = xml_file.read()
soup = BeautifulSoup(data, "lxml-xml")
W tym momencie cały kod XML wczytany został do obiektu soup. Drugim parametrem konstruktora jest nazwa parsera. Dla HTMLa powinniśmy używać innego parsera, dla XMLa innego.
W tym momencie możemy dostać się do poszczególnych znaczników korzystając z notacji kropki. Innymi słowy mówiąc, dostajemy się do nich podobnie jak do pól w każdym obiekcie.
>>> print(soup.website)
<website>kamil.kwapisz.pl</website>
>>> print(soup.website.text)
kamil.kwapisz.pl
Obiekt oddaje również zagnieżdżenie znaczników:
>>> print(soup.blog.website.text)
kamil.kwapisz.pl
>>> print(soup.blog.posts.post)
<post>
<author>Kamil Kwapisz</author>
<name>Web Scraping w Pythonie</name>
<url>http://kamil.kwapisz.pl/web-scraping-python/</url>
</post>
Napotykamy tutaj jednak pewną przeszkodzę, gdyż są tutaj dwa znaczniki <post>.
Jednym ze sposobów radzenia sobie z taką sytuacją jest skorzystanie z atrybutu children:
>>> for post in soup.blog.posts.children:
print(post, end="")
<post>
<author>Kamil Kwapisz</author>
<name>Web Scraping w Pythonie</name>
<url>http://kamil.kwapisz.pl/web-scraping-python/</url>
</post>
<post>
<author>Kamil Kwapisz</author>
<name>PEP 8 – czyli gramatyka dla programisty</name>
<url>http://kamil.kwapisz.pl/gramatyka-dla-programisty/</url>
</post>
Inną metodą parsowania kodu XML jest wyszukanie konkretnch znaczników. Służy do tego metoda find_all, którą można również używać tak:
>>> post_names = soup('name')
>>> print(post_names)
[<name>Web Scraping w Pythonie</name>, <name>PEP 8 – czyli gramatyka dla programisty</name>]
W przypadku próby odszukania znacznika, który nie istnieje, lista będzie pusta:
Co zwraca listę wszystkich znaczników o tej nazwie.
>>> print(soup('brak_znacznika'))
[]
Jeżeli wiesz, że w dokumencie jest tylko jeden znacznik, którego szukasz (lub zależy Ci na znalezieniu pierwszego wystąpienia) możesz użyć metody find, która zwróci tylko jeden znacznik:
>>> lang = soup.find('lang')
>>> print(lang)
<lang>polish</lang>
Wykorzystanie XML
Tak jak JSON był notacją danych używanych w REST API, tak XML wykorzystywany jest w protokole SOAP do przekazywania danych. Czasem stosuje się go nawet w REST API, jest to jednak raczej rzadkie zjawisko.
Innym popularnym wykorzystaniem XMLa są sitemapy, czyli mapy witryn internetowych. O sitemapach przeczytać możesz w artykle o web crawling.
Powoli zapominanym wykorzystaniem XMLa jest również RSS.
Zalety i wady XML
Zalety:
- dobre zobrazowanie hierarchii (dziedziczenia) – struktura drzewa
- dobrze ustandaryzowany
- łatwo zweryfikować, czy nie ma błędów
- czytelność
Wady:
- brak jednoznacznej możliwości przekazania wartości null
- brak rozróżnienia typów danych (np stringów od liczb)
- trudniejszy w parsowaniu
JSON vs XML
Mówiąc o zaletach i wadach JSONa i XMLa trudno pominąć temat porównania ich ze sobą.
JSON jest szybszym i bardziej „luźnym” sposobem przekazywania danych. Dużo łatwiej go parsować, jest również (przynajmniej zdaniem większości) bardziej czytelny niż XML. Nie niesie ze sobą jednak wszystkich możliwości jakie ma XML.
Oba rozwiązania mają swoje mocne i słabe strony, dlatego każdy programista powinien dobrać sposób zapisu danych do konkretnego przypadku.
Zdecydowanie warto potrafić radzić sobie i z jednym i z drugim 🙂
Dzięki, że dotrwałeś do końca!
Mam nadzieję, że artykuł Ci się spodobał 🙂 Daj znać!
Pozdrawiam
Kamil Kwapisz
Hej Kamil 👋,
Bardzo fajny artykul. Uzywalem XML przy swoim pierwszym projekcie ToDo listy napisanej w JS i Ajax.
Z tego co pamietam to uczac sie napotkalem wiele problemow podczas parsowania pliku XML. Jednym z nich byl fakt wystepowania nodów z białymi znakami kiedy tych nodów w kodzie w ogóle nie było 🤔.
Czy napisałes juz artykul o REST API? Jesli nie to chetnie bym poczytal o tym co to jest i jak sie tego uzywa, tworzy 🤓.
Bardzo przyjemnie czyta mi sie artykuły na twoim blogu ☺️.
Cześć ✋.
Hej Mateusz!
Dzięki 🙂
Nie napisałem jeszcze artykułu o Rest API, jednak z przyjemnością to zrobię!
Pozdrawiam 🙂