Wrzasq.pl

Od podstaw: XML

Thursday, 16 June 2016, 10:47

XML

XML to "rozszerzalny język znaczników" (ang. eXtensible Markup Language). Oznacza to, że jest to język uniwersalny przeznaczony do tworzenia języków oznaczeń - sam w sobie jest jedynie zbiorem zasad składni, definiuje pewne mechanizmy rządzące dokumentem, nie definiuje za to żadnych znaczników ani atrybutów. Innymi słowy XML określa jedynie format zapisu, a nie format samych danych. Robią to dopiero języki oparte na XML-u takie jak XHTML, RSS i wiele innych. Sam XML jest pochodnym SGML, a ten z kolei wywodzi się z GML. Nie będę ich tutaj omawiał, jednak ich idea jest podobna. Zostały one opracowane w celu przechowywania i współdzielenia dokumentów w jednolity sposób na przestrzeni lat. XML jest w gruncie rzeczy uproszczoną wersją SGML - ogranicza jego implementacje tylko do domyślnej składni, ujednolica wiele zagadnień (jak chociażby "puste" tagi). O XML-u pewnie obiło się wielu osobą o uszy, często jednak nie zdają sobie sprawy jak ważne są niektóre jego aspekty. Widać to chociażby w przypadku stron WWW tworzonych w tej technologii (korzystając z języka XHTML).

Podstawowym błędem jaki popełnia wiele osób zaczynających pracę z XML-em to traktowanie go jak zwykłego tekstu. Owszem - dokumenty XML zazwyczaj można edytować w zwykłym edytorze tekstu, jako znaki specjalne wykorzystują znaki z zakresu ASCII (<, > i kilka innych), ale wszystkie te znaki mają określone znaczenia, struktura dokumentu jest określona. Ich znaczenie, oraz wzajemne relacje (chociażby samej struktury drzewa opisanej niżej) powodują, że nieraz nierozważne modyfikowanie zawartości dokumentu prowadzi do zapisania go z błędami.

Struktura dokumentu

Tak, jak już wspomniałem strukturą dokumentu XML jest drzewo. Każda dana w dokumencie stanowi węzeł drzewa. Korzeniem tego drzewa jest element (o tym czym są elementy za chwilę). Poniżej przedstawiam opis tylko najważniejszych typów węzłów w drzewie XML - jest ich więcej (na przykład sam dokument też jest rodzajem węzła, węzłem też są komentarze i prolog dokumentu). Opis ten ma na celu jedynie słowne wyjaśnienie podstawowych pojęć - technicznych specyfikacji i dokładnych standardów należy szukać na stronie grupy roboczej XML przy W3C.

Elementy

Podstawowym typem węzła jest element. Każdy dokument ma co najmniej jeden element, wspomniany korzeń. Elementy na pewno wszyscy dobrze znają jako używane w (X)HTML-u znaczniki (tagi). Grupują one pozostałe elementy jako swoją zawartość - elementy to jedyne węzły, które mogą mieć potomków (czyli węzły w drzewie "podpięte" pod nie).

Element obejmuje wszystko od znacznika początkowego, do końcowego. Jest to jedna z różnic między SGML, a XML - ten pierwszy dopuszczał istnienie znaczników otwierających bez odpowiadających im znaczników końcowych (najprostszym przykładem jest element BR z języka HTML). Znacznik zapisuje się wstawiając jego nazwę między nawiasy trójkątne (<, >), a znacznik końcowy oznacza się dopisując do nazwy z przodu znak /.

W przypadku XMLa puste znaczniki również muszą posiadać znacznik końcowy, dopuszczalna jest jednak skrócona forma zapisu. Następujące dwa fragmenty dokumentów są poprawnie zapisanymi elementami br w XHTML-u (a więc i XML-u):

<br></br>
<br/>

Atrybuty

Atrybuty opisują pewne właściwości elementów. Zapisuje się je w formie nazwa="wartość" (zamiast cudzysłowów dopuszcza się stosowanie apostrofów). Jest to kolejna zmiana w stosunku do SGML - tam wartości można było zapisywać bez ograniczników (w przypadku gdy wartość nie zawierała białego znaku), a nawet bez wartości (na przykład atrybut selected w HTML). W XML każdy atrybut musi mieć wartość, tak więc aby zaznaczyć wybraną opcję w liście rozwijanej w XHTML należy napisać:

<option value="foo" selected="selected">Wybrana</option>

Tekst

Najważniejszy w każdym dokumencie jest przekaz. W przypadku XML często chodzi o przekaz tekstowy. Wartość tekstowa danego elementu jest wpisywana między jego początkowy i końcowy znacznik. Istnieją dwa sposoby wprowadzania tekstu. Może on zostać zapisany bezpośrednio, trzeba wtedy jednak pamiętać, o użyciu encji (o tym za chwilę) w przypadku znaków specjalnych XML-a. Drugi sposób to użycie tak zwanej sekcji CDATA:

<element><![CDATA[
    <foo>
]]></element>

Tekst zapisany w sekcji CDATA nie zostaje przetworzony jako XML - w tym wypadku <foo> jest traktowane jako zwykły tekst, a nie element. W sekcji takiej jednak nie można (w żaden sposób) przechowywać ciągu ]]>, jeśli więc chcemy zapisać go musimy skorzystać z dwóch sekcji CDATA oddzielonych zwykłym tekstem:

<element>
<!--
ten element po przetworzeniu będzie miał następującą zawartość tekstową:

pierwszy fragment tekstu
]]>
drugi fragment tekstu

 -->
<![CDATA[
pierwszy fragment tekstu
]]>]]&gt;<![CDATA[
drugi fragment tekstu
]]>
</element>

Encje

Ostatnim z najważniejszych typów węzłów są encje - ang. entity. Są to odwołania do wcześniej zdefiniowanych identyfikatorów. Odwołania takie zostają w czasie przetwarzania podmienione z wartościami danych identyfikatorów. Podstawowym zastosowaniem jest wstawianie do dokumentów znaków specjalnych. Istnieje pięć pre-definiowanych encji, które dają możliwość zapisania wszystkich znaków używanych przez XML jako specjalne:

&lt; <
&gt; >
&amp; &
&quot; "
&apos; '

Pierwsze dwa znaki są używane jako ograniczniki znaczników, ampersand jest używany do rozpoczęcia zapisu encji (na przykład, żeby zapisać &amp; należy odwołać się podwójnie, przez &amp;amp;). Ostatnie dwa znaki są używane jako ograniczniki wartości atrybutów - tak na prawdę poza atrybutami nie trzeba ich zastępować i można pisać bezpośrednio; ponadto jeśli ogranicznikiem wartości danego atrybutu jest cudzysłów, to nie trzeba podmieniać apostrofów, tak więc poniższy zapis jest w pełni poprawny:

name="&quot;rock'n'roll&quot;"

Oprócz tego XML daje też możliwość zapisania dowolnego znaku jako odwołanie do tablicy Unicode używając kodu danego znaku:

&#DDD; W zapisie dziesiętnym.
&#xHHH; W zapisie szesnastkowym.

Tak więc znak < (&lt;) możemy zapisać również jako &#60; lub jako &#x3C;.

Document Object Model

Sam XML określa fizyczną strukturę dokumentu, jednak w reprezentacji cyfrowej jest to pojęcie niezwykle ogólne. Dlatego aby ustandaryzować pracę z dokumentami XML z poziomu kodu programu stworzono interfejs programistyczny o nazwie Document Object Model - w skrócie DOM. Jest on powszechnie używany i zaimplementowany na chyba wszystkie ważniejsze platformy, a w przypadku środowisk do pracy w środowisku internetowym (PHP5, JavaScript, Java i wiele innych) praktycznie jest on standardem. API to określa metody dostępu do węzłów, ich modyfikacji, tworzenia i wiele innych operacji.

Jeśli mamy zamiar wykorzystywać w naszym oprogramowaniu formaty oparte na XML-u to DOM jest podstawą. Korzystając z niego mamy pewność, że przetwarzamy dokument we właściwy sposób (oczywiście pomijając możliwość błędu w samej bibliotece naszego środowiska ;)), a ponadto ułatwi nam to ewentualną migrację do nowego środowiska, albo reprodukcję kodu - w każdym DOM zadziała w taki sam sposób i korzysta się z niego również w niemal taki sam sposób w każdej dostępnej implementacji (takie jest założenie ale oczywiście istnieją zazwyczaj drobne różnice w zależności od języka).

xml:id

Bardzo ważnym rozszerzeniem podstawowej standaryzacji XML jest xml:id. Najprościej rzecz ujmując określa ono zasady identyfikacji elementów w dokumencie. W skrócie, który jednak nie ujmuje nic ważnego z całości, xml:id określa typ atrybutu, który jest unikalny w skali dokumentu - czyli posługując się jego wartością jesteśmy w stanie znaleźć szukany element (nie ma drugiej takiej wartości). W większości języków opartych na XML-u używa się do tego celu atrybutu id, jednak tutaj należy zaznaczyć bardzo ważną sprawę - sam dokument xml:id nie określa nazwy atrybutu, a jedynie jego typ. Oznacza to, że język musi określić, który atrybut będzie w nim oznaczał identyfikator. Na przykład poniższy kod wypisze bar, a nie foo!:

$dom = new DOMDocument();
$dom->loadXML('<!DOCTYPE element [

<!ELEMENT element (element*)>
<!ATTLIST element
    id      CDATA   #IMPLIED
    name    ID      #IMPLIED
>

]>
<element>
    <element id="bar" name="foo" />
    <element id="foo" />
</element>');

echo $dom->getElementById('foo')->getAttribute('id');

Sekcji DOCTYPE nie będę na razie tłumaczył - definiuje ona dla naszego typu dokumentu znacznik element, który może zawierać dwa atrybuty: id i name. Jednak jako identyfikator podaje ten drugi. Co więcej - bez tej sekcji w dokumencie w ogóle nie będziemy mogli wyszukiwać elementów, gdyż id nie jest nawet domyślnie atrybutem typu xml:id - nie jest niż żaden atrybut. Dlatego właśnie ważne jest zrozumienie, czym XML sam w sobie jest dla dokumentu - jedynie formatem zapisu, a to my musimy sami zatroszczyć się o jego prawidłową (oczekiwaną przez nas) interpretację pod kątem zawartości.

DOM

Rozszerzenie xml:id ma również bardzo duże znaczenie w aspekcie korzystania z interfejsu DOM. Jak widać w powyższym przykładzie interfejs ten udostępnia metodę getElementById() - to właśnie dzięki niej możemy bez trudu odnaleźć element o podanym przez nas identyfikatorze.

Przestrzenie nazw

Kolejnym ważnym mechanizmem rozszerzającym podstawowe zasady funkcjonowania XML-a są przestrzenie nazw. Idea ta jest pewnie znana z wielu języków programowania i w przypadku XML-a pełni podobną rolę - grupowanie identyfikatorów z jednego języka w jego przestrzeni nazw. Tyle, że w przypadku XML-a jest to znacznie bardziej ważne - jak już wiele razy zaznaczałem pracując z XML-em praktycznie samodzielnie tworzymy własny język, dlatego ważne jest aby zgrupować wszystko to, co w nim definiujemy i odizolować od reszty. Mechanizm przestrzeni nazw jest nieco inny niż te znane z języków programowania jak chociażby C++ - tutaj przestrzenią nazw jest po prostu prefiks nazwy danego elementu, lub atrybutu. Użycie przestrzeni nazw nie ładuje nam jej, nie dołącza żadnej biblioteki - po prostu grupuje dany element, lub atrybut. Jest to nieco mylące, szczególnie na początku, ale należy pamiętać, że XML sam w sobie jest kompletnie statyczny - to język formatowania dokumentów, a nie język programowania, który określa wykonywanie czynności.

Jeszcze bardziej pokręcony może się wydawać na początku sposób użycia tej techniki. Samą przestrzenią nazw jest URI, natomiast w dokumencie tworzy się dla niej lokalny identyfikator:

<root xmlns:foo="http://localhost/" foo:bar="test" />

W tym wypadku tworzymy w dokumencie identyfikator foo dla przestrzeni nazw http://localhost/. Tworzenie przestrzeni nazw w dokumencie odbywa się za pomocą atrybutu xmlns w formie xmlns:identyfikator. Możemy także użyć samego atrybutu xmlns, ma to miejsce chociażby w przypadku stron napisanych w XHTML-u:

<html xmlns="http://www.w3.org/1999/xhtml" />

W ten sposób definiujemy domyślną przestrzeń nazw. Jednak co jeszcze bardziej mylące - dana przestrzeń nazw nie jest żadnym fizycznym adresem (może, ale nie musi) - może być to nie istniejący URI, co więcej - nawet nie musi być to realny URI, musi być jedynie poprawny składniowo (ale oczywiście zalecane jest, aby pod adresem wskazywanym przez przestrzeń nazw znajdywał się jakiś powiązany z nią zasób).

Przestrzenie nazw w XML dają ogromne możliwości - pozwalają na zagnieżdżanie elementów z różnych formatów w jednym dokumencie. Jest to jedna z największych korzyści jakie płyną z XHTML, który tym właśnie się różni od HTML-a, że jest aplikacją XML. Można na przykład osadzić obraz SVG bezpośrednio wewnątrz dokumentu XHTML:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
    <head>
        <title>Przykład osadzania dokumentów XML</title>
    </head>
    <body>
        <h1>Grafika SVG osadzona bezpośrednio w dokumencie XHTML</h1>
        <svg:svg version="1.1" baseProfile="full" width="300px" height="200px">
            <svg:circle cx="150px" cy="100px" r="50px" fill="#ff0000" stroke="#000000" stroke-width="5px"/>
        </svg:svg>
    </body>
</html>

Aby obejrzeć rezultaty potrzebna będzie przeglądarka z obsługa formatu SVG (na przykład Opera), a plik należy zapisać z rozszerzeniem .xhtml. Przykład zaczerpnięty ze strony https://jwatt.org/svg/demos/xhtml-with-inline-svg.xhtml, nieco oczyszczony. Na ekranie powinno się pojawić czerwone koło z czarną obwódką.

Walidacja

Bardzo ważnym elementem przetwarzania dokumentów XML jest walidacja, czyli sprawdzanie ich poprawności. Sam fakt, iż dokument udało się załadować jako strukturę danych świadczy jedynie, że jest to poprawnie zapisany dokument XML. Ponieważ w XML-u sami decydujemy o tym jaką strukturę mają mieć dane zapisane w dokumencie, sam procesor XML (mechanizm ładujący i przetwarzający dokumenty) nie jest w stanie sprawdzić ich poprawności pod kątem semantycznym, zbadać ich zależności. Do tego celu należy stworzyć definicje typów danych zawartych w dokumentach.

Sposobów na to jest kilka, ja przedstawię tutaj trzy najważniejsze. Nie będę ich zbyt szczegółowo omawiał, ponieważ każdy z nich to temat na wiele osobnych stron artykułów.

DTD

Pierwszym sposobem opisu jest DTD - Document Type Definition. Jest to natywny sposób opisu zawartości dokumentu wywodzący się jeszcze z SGML - jest on bardzo prosty i prymitywny, jednak przez to również ograniczony. To właśnie w DTD została zapisana definicja danych w przykładzie obrazującym działanie xml:id. DTD ma jednak kilka cech, które stawiają je ponad pozostałymi sposobami opisu XML:

  • Jest to natywny sposób opisu dla XML (i SGML). Pozostałe metody wymagają obsługi przez dodatkowe moduły/biblioteki. DTD daje możliwość sztywnego połączenia dokumentu ze jego definicją.
  • Można go załączać zarówno bezpośrednio w dokumencie, albo jako odnośnik (wystarczy przejrzeć pierwszą linijkę większości poprawnie stworzonych stron internetowych).

Jednak jak już wspomniałem DTD jest bardzo ograniczone i pozwala tylko na podstawowy zakres definiowania struktury dokumentu. Ponadto używa on składni SGML, co w przypadku osób chcących pracować z samym XML-em może stwarzać niepotrzebne zamieszanie.

XML Schema

Nowszą technologią jest XSD (XML Schema Definition). Daje ona ogromne możliwości, znacznie większe niż te z DTD. Ponadto definicja stworzona przy pomocy tego języka jest sama w sobie również dokumentem XML, więc jest to wygodniejsze rozwiązanie dla osób obeznanych z XML-em.

Ma ono jednak swoje wady. Po pierwsze nie da się załączyć definicji XML Schema do dokumentu. Walidacja na podstawie takiego schematu odbywa się "na życzenie", czyli należy po załadowaniu w kodzie naszego dokumentu wskazać procesorowi XML dodatkowo nasz schemat. Poza tym jako iż jest to również język oparty na XML, to i tak posiada on swój własny DTD opisujący jego składnię.

Relax NG

Podobnym rozwiązaniem do XSD jest Relax NG. Poza tym, że różni się składnią, to sama idea jest bardzo podobna, więc posiada on pod względem technicznym podobne wady i zalety. Jedyną większą różnicą jest fakt, iż język ten posiada drugą składnię, która nie jest składnią XML (kompaktowa).

XML a (X)HTML

Jaka jest relacja między XML-em, a HTML-em? Otóż bezpośredniej nie ma w ogóle. HTML to język oparty na SGML-u. Pisanie w nim jest nieraz wygodniejsze niż pisanie w XML-u, jednak wiąże się to z wadami ze strony technicznej - niejednoznaczność i nie konsekwentność w strukturze dokumentu. Implementacją HTML-a, w sztywnych regułach XML-a jest XHTML - jest to pełnoprawna aplikacja XML, zatem korzystanie z niego ma wiele zalet (możliwość zagnieżdżania dowolnych innych aplikacji XML, oraz zagnieżdżania w innych aplikacjach XML), łatwe przetwarzanie (możliwość skorzystania z interfejsu DOM). Oczywiście trzeba pamiętać o zasadach przekształcania dokumentów HTML w XHTML.

DOM a (X)HTML

Nie ulega wątpliwości, że na co dzień w sieci formatem XML, który wymaga najwięcej przetwarzania jest właśnie XHTML. Strony internetowe zbudowane przy pomocy XHTML-a można przetwarzać standardowymi metodami udostępnianymi przez DOM. Jednak nie jest to zbyt wygodne - większość elementów posiada bardzo specyficzne własności. Dla języka XHTML stworzono dlatego specjalne rozszerzenie interfejsu DOM (jego implementacje działają zazwyczaj również z dokumentami HTML) - opisuje ono dodatkowe metody elementów definiowanych przez XHTML pozwalając na bardzo łatwe manipulowanie stronami chociażby przy tworzeniu aplikacji webowych w technologii AJAX.

Technologie XML

XML daje ogromne możliwości. Być może nawet nie wiesz jak szeroko jest on używany w dzisiejszym oprogramowaniu. Jego prostota i elastyczność sprawiają, że idealnie nadaje się na przykład jako format do protokołów sieciowych. Przedstawię tutaj tylko wybrane z różnych dziedzin przykładu użycia XML-a. Na co dzień jest on używany w przeróżnych celach i znajomość jego to praktycznie podstawa w dziedzinie przetwarzania danych.

SVG

Jest to format (którego użyłem w tym artykule jako przykład) grafiki wektorowej. Grafika wektorowa ma tę zaletę, że jest zapisywana w postaci matematycznej, dzięki temu można ją przeskalować do dowolnej wielkości bez utraty jakości ani informacji. SVG to otwarty standard, a dzięki temu, że jest oparty na XML-u można łatwo generować obrazy SVG w programach. Nadaje się bardzo dobrze do tworzenia wszelkiego rodzaju schematów i wykresów, gdzie dane powinno się dać łatwo zmienić, jednak można go z powodzeniem używać do dowolnego innego rodzaju grafik.

SOAP

SOAP to protokół typu RPC - Remote Procedure Call. Daje on możliwość przesyłania wywołań procedur przez sieć, oraz odbierania rezultatów takich zapytań. W rezultacie można tworzyć aplikacje korzystające z serwera za pośrednictwem wygodnego interfejsu programistycznego wyglądającego jak zwykłe wywołania biblioteczne. Przykładem jest chociażby opisywane przeze mnie Allegro WebAPI.

Jabber

Jabber to oparty na XML, uniwersalny i elastyczny protokół komunikacyjny. Wykorzystywany jest przede wszystkim w komunikatorach internetowych (dzięki obsłudze "transportów" daje możliwość korzystania także z innych sieci jako usług serwera). Korzystają z niego między innymi polskie AQQ, czy Tlen.

ODF, OOXML

Niewiele osób zdaje sobie sprawę, że obecnie większość popularnych formatów biurowych również korzysta z XML-a. OpenDocument (ODF) to format używany przez pakiet OpenOffice.org. Jest to oficjalny międzynarodowy standard ISO. Z kolei mało kto z korzystających na co dzień z najnowszej wersji MS Office wie, że Microsoft również do swoich dokumentów używa formatów opartych na XML-u. Format ten nazywa się OOXML i również jest standardem ISO.

Bardzo prosto można się o tym przekonać, wystarczy zmienić rozszerzenie pliku któregokolwiek z tych formatów na .zip - pliki te są po prostu archiwami ZIP zawierającymi dokumenty XML.

XML 1.1

Opisywana przeze mnie tutaj wersja XML-a to 1.0. Istnieje również wersja 1.1. Na pierwszy rzut oka niewiele się zmieniło i ogólne zasady nadal są takie same. Jednak zmiana wersji niesie kilka zmian, które powodują, że nie każdy poprawny dokument XML 1.0 jest poprawnym dokumentem XML 1.1 i to sprawia, że nowa wersja nie zdobywa na razie popularności - tak na prawdę nie wnosi ona zbyt wiele, więc nie ma po co zmieniać wszystkiego i narażać się na niekompatybilność ze starszymi wersjami dokumentów.

Podstawowa zmiana to filozofia dopuszczalnych nazw - w przypadki wersji 1.0 wszystko co nie było dozwolone było zakazane. W przypadku wersji 1.1 wszystko co nie jest zabronione jest dozwolone. Pozwala to na przykład na użycie wielu dodatkowych znaków Unicode. Oprócz tego zmieniła się filozofia dotycząca wielu znaków kontrolnych - wiele znaków, których nie można było używać poprzednio, teraz można używać w tekście za pomocą encji (jednak nadal nie można używać znaku #0, nawet jako encji). Jednak z drugiej strony wiele znaków kontrolnych, które można było używać bezpośrednio, teraz trzeba przekształcać na encje, co właśnie powoduje problemy.

Ogólnie, jeśli nie potrzebujemy, to nie ma żadnej realnej potrzeby przenoszenia się na nowszą wersję - nie jest to żadna rewolucja, a jedynie zmiany wprowadzone (niestety) po czasie.

Na koniec

Podsumowując, jeśli mamy zamiar obsługiwać i przetwarzać dokumenty za pośrednictwem sieci, praktycznie na pewno zetkniemy się z XML-em. A jeśli już musimy z nim pracować to warto go dobrze znać. Brak podstawowej wiedzy na temat jego działania prowadzi często do wypaczonego podejścia, a XML nie jest wcale trudny, więc dobrze jest poświęcić chwil kilka na zgłębienie jego przynajmniej podstawowych mechanizmów.

Tags: , , ,