Wprowadzenie do XML
XML zdołał już na stałe zadomowić się w środowisku IT. Szczególnie często spotykany jest w internecie np. przy wymianie danych w B2B (ang. business-to-business). Sam w sobie jest tylko standardem zapisu plików tekstowych w postaci znaczników (podobnie jak HTML), ale wraz w innymi technologiami jak: DTD, XSD, XPath, XSLT, DOM, SAX, XQuery daje więcej przydatnych możliwości (walidacja, analizowanie/wyszukiwanie/wskazywanie danych, transformacja, programowanie, zapytania), interoperatywność (formalnie norma ISO/IEC 9075-14:2008) z systemami bazodanowymi (Oracle, IBM DB2, SQL Server oraz natywne NXD np. eXist) i wiele innych możliwości/zastosowań (np. Microsoft Windows Presentation Foundation, Apache Ant).
Autor: Grzegorz Szpetkowski
Źródło: http://mars.iti.pk.edu.pl/~mfi/?p=549
XML (oficjalna strona W3C) to:
- Akronim od Extensible Markup Language
- Standard W3C normatywnie określony przez rekomendacje m.in. XML 1.0 (niestety oficjalnego polskiego tłumaczenia obecnie nie ma, stąd brakuje oficjalnych polskich odpowiedników dla sformułowań typu well-formed XML, valid XML, schema itd.)
- Uproszczenie i podzbiór SGML (Standard Generalized Markup Language), każdy XML jest jednocześnie dokumentem SGML, ale nie na odwrót
- Technologia pozwalająca przechowywać dane w formie tekstu w ramach drzewiastej struktury
- Metajęzyk i punkt wyjścia dla takich aplikacji jak XSL, XSD (XML Schema), SVG, MathML, RSS, Atom, XHTML, SOAP, WSDL i OpenDocument (ODF).
Bardzo istotną cechą XML jest pełna niezależność od platformy, to bez znaczenia czy używamy serwera aplikacji JBoss opartego na Red Hat Enterprise Linux, Debian’a z Apache+PHP, platformy .NET na Windows 2008 Server, Perl/CGI, FreeBSD+Ruby on Rails itd. Praktycznie każdy język programowania posiada w bibliotece standardowej obsługę przetwarzania XML np. JAXP (Java API for XML Processing) i JAXB (Java Architecture for XML Binding) w Javie. W teorii istnieją dwie wersje XML’a tzn. 1.0 i 1.1, ale w praktyce nigdy się spotkałem żeby ktokolwiek używał tego drugiego, innymi słowy standardem przemysłowym jest XML 1.o.
Kolejną cechą jest kładzenie nacisku na stosowanie kodowania znaków Unicode, każdy parser (inaczej procesor XML, aplikacja, która potrafi czytać XML) wewnętrznie reprezentuje znaki w tym standardzie. Oznacza to tyle, że XML jest całkowicie uniwersalny, to nieważne czy nasz system jest zlokalizowany w Japonii, czy we Włoszech, wszystkie znaki diakrytyczne będą poprawnie odczytywane.
XML może być stosowany wszędzie tam, gdzie trzeba przechowywać i przesyłać dane tekstowe zorganizowane strukturalnie np. prognoza pogody. World Weather Online jest jednym z serwisów, który potrafi w ramach usługi Weather API przekazywać aktualne dane pogodowe (temperatura, opady, wiatr, wilgotność powietrza etc.) z dowolnego miejsca na Ziemi. Dane są dostarczane w formie XML (dostępne jest także JSON i CSV), który w żaden sposób nie określa w jaki sposób mają być wyświetlane, czy zrobimy to na stronie WWW, aplikacji Windows Forms, w Qt, urządzeniu mobilnym itd. to już nasza sprawa.
W ten sposób trzecią cechą XML’a jest elastyczność, a także lekkość, strukturę dokumentu możemy dowolnie modelować przez zagnieżdżanie elementów i stosowanie atrybutów, a także przetwarzać np. filtrować przez XSLT. Powyższe cechy sprawiły, że XML szczególnie dobrze sprawdza się w usługach sieciowych np. typu REST. Pomimo, że format znacznikowy „z definicji” generuje duże rozmiary plików, to wiele framework’ów np. JBoss RESTEasy pozwala wykorzystać kompresowanie (XML bardzo dobrze się kompresuje np. via deflate) na protokole HTTP, które jest zupełnie niewidoczne na odbiorcy usługi (transparetne kompresowanie HTTP).
Warto także zauważyć, że XML zyskał bardzo szeroką akceptację całego środowiska IT włącznie z Microsoft’em, dzięki czemu można śmiało go nazwać standardem przemysłowym (ang. industry standard).
Przykładowy, prosty XML można napisać własnoręcznie np. polecam na początek w Notepad++ (z wybranym kodowaniem UTF8 bez BOM):
<?xml version="1.0" encoding="UTF-8"?> <!-- deklaracja XML -->
<ksiazki> <!-- znacznik otwierający element główny -->
<ksiazka id="WG-001">
<tytul>Symfonia C++</tytul>
<isbn>83-7366-130-1</isbn>
<autor>Jerzy Grębosz</autor>
</ksiazka>
<ksiazka id="WG-002">
<tytul>Thinking in C++</tytul>
<isbn>83-7197-709-3</isbn>
<autor>Bruce Eckel</autor>
</ksiazka>
<!-- kolejne książki -->
</ksiazki> <!-- znacznik zamykający element główny -->
Można bez przeszkód usuwać białe znaki takie jak: spacje, tabulacje, znaki nowego wiersza i powrotu karetki, które mają służyć tylko człowiekowi, do łatwej edycji dokumentu (do samego odczytu można posłużyć się przeglądarka WWW, która automatycznie pokazuje wcięcia, a także pozwala zwijać/rozwijać elementy), dla parsera wszystko jedno czy cały XML zapiszemy w jednej linii, czy z wcięciami. W dalszej części wpisu zajmę się:
- zasadami budowy poprawnego XML’a (każdy dokument musi well formed, jest to więc podstawa)
- przestrzeniami nazw, które pozwalają umieścić więcej niż jedno słownictwo (ang. vocabulary) w dokumencie XML
Well formed XML
Co niezmiernie ważne obowiązują pewne zasady jak ma wyglądać poprawny XML (ang. well-formed). Jeśli nie będzie, to parser go odrzuci, nie ma tak jak w HTML’u, że przeglądarka mimo błędów stara się „domyśleć” o co miało chodzić, tutaj dane muszą być poprawne (pójściem o krok dalej jest stosowanie mechanizmu walidującego np. XSD zawartość dokumentu, przykładowo możemy określić, że dany element może zawierać tylko liczby całkowite ujemne, albo datę w zadanym formacie, jaka ma być struktura dokumentu i wiele innych). Najbardziej podstawowym obiektem są elementy np.:
<a>to jest zawartość elementu o nazwie a</a>
Pierwszą ważną informacją jest to, że element należy zamknąć znacznikiem (chyba, że jest pusty, wtedy można stosować skróconą postać). Co ważne to my decydujemy o nazwie elementów, w przypadku HTML mamy zamkniętą listę, tutaj można określić prawie dowolną nazwę:
- nie może być pusta
- musi zaczynać się od litery (również niełacińskie, choć wg niepisanego prawa zazwyczaj stosuje się nazwy tylko z ASCII) albo znaku podkreślnika ‘_’, inne znaki są niedozwolone
- dalej może zawierać to samo co wyżej oraz cyfry i znaki ‘-’, pozostałe znaki są niedozwolone w wyłączeniem znaku dwukropka ‘:”
- znak dwukropka jest zarezerwowany do obsługi przestrzeni nazw, nie wolno go używać jako samej nazwy
- nazwa nie może zaczynać się od xml, XML, xML, ani żadnej kombinacji np. xml_element jest niedozwolone
Jeżeli element jest pusty (bez zawartości) np. <a></a>, to możemy go zapisać równoważnie <a/> ew. <a/ >. Dowolnemu elementowi można przypisać (dowolnie długą) listę atrybutów należących do niego np. <a id1=”1″ id2=”2″/>. Poprawne zapisy atrybutu to (można dodawać białe znaki):
nazwa="wartość" nazwa='wartość'
inne (np. wartości nie ujęte w cudzysłów, ani apostrof) są zabronione. Dla danego elementu nie można umieścić więcej niż jeden atrybut o takiej samej nazwie np. <a id1=”1″ id1=”2″/> jest zabronione. Nazwy atrybutów podlegają takim samym ograniczeniom jak nazwy elementów.
Łatwo zauważyć, że XML jest nieco bardziej „restrykcyjny” od HTML’a (ang. hard-and-fast rules), idąc dalej w XML w przeciwieństwie do HTML’a wielkość liter ma znaczenie innymi słowy zapis <P>witaj</p> w XML jest błędny. Elementy muszą być też poprawnie zagnieżdżone w sobie np. w XML zapis <b>tes<em>k</b>t</em> jest błędny. Chodzi o to, że XML ma reprezentować drzewiastą strukturę, każdy element może zawierać:
- PCDATA, czyli po prostu tekst
- inne elementy
- nieparsowaną sekcję CDATA
- zawartość mieszaną czyli kombinację w.w.
Elementem głównym nazywamy ten, który jest najbardziej nadrzędny, może być tylko jeden główny element. Istnieje także ograniczenie do zawartości elementów i atrybutów, dla tych pierwszych mamy:
⇒ nie można umieścić znaków & i < zamiast nich należy stosować maskowanie odpowiednio & i <, często także maskuje się znak > przez >, choć zupełnie nie jest to konieczne. Można też użyć sekcji CDATA.
dla atrybutów:
⇒ to samo co przy elementach, w dodatku w zależności od użytego ogranicznika tzn. ” i ‘ nie można wartości atrybutu zapisać tego ogranicznika, innymi słowy błędny jest zapis <a id=”12″3″/>, można to zapisać przez <a id=’12″3′/> albo z użyciem encji maskujących odpowiednio " i ' dla ” i ‘ tzn. <a id=”12"3″/>.
Zatem w XML’u występuje pięć wbudowanych encji nazwanych (ang. character entities):
- < dla <
- > dla >
- & dla &
- ' dla ‘
- " dla „
Dodatkowo możemy zapisywać znaki w encjach numerycznych Unicode na dwa sposoby:
- encja decymalna przez &#d; np. ©
- encja heksadecymalna przez &#xh; np. © (można także ©, ale x musi być z małej litery)
Należy jednak zważyć na to, że nie wszystkie znaki są dostępne, rekomendacja XML 1.0 określa, że możliwymi do użycia są:
- #x9, #xA, #xD oraz przedziały: [#x20; #xD7FF] ∪ [#xE000; #xFFFD] ∪ [#x10000; #x10FFFF]
Jedną z podstawowych różnic między XML 1.0, XML 1.1, jest to, że ten drugi potrafi obsługiwać większą pulę znaków Unicode. Wszystkie znaki tego standardu znajdziesz na tej stronie (są określane w systemie szesnastkowym).
Nieco wyprzedzając temat (jest to tylko wstęp do XML) jako ciekawostkę mogę podać, że m.in. w DTD możemy tworzyć własne encje nazwane, stąd w XHTML 1.0 można stosować takie encje jak np.: ←, κ (pełną listę znajdziesz tutaj, w sekcji „Character mnemonic entities” znajdziesz trzy encje wewnętrzne DTD prowadzące do plików ent). Oczywiście nic nie stoi na przeszkodzie by np. także w kodzie XSLT (który de facto jest przecież XML’em) definiować własne encje.
Jeśli nie chcemy używać encji maskujących można zastosować nieparsowaną sekcję CDATA, dzięki której tekst może zostać w takiej postaci jak był pierwotnie. Sekcję otwiera się przez <![CDATA[, a zamyka przez ]]>. Mimo pożytku jaki ze sobą niesie powoduje dodatkową złożoność, np. nie można w wartości umieścić ]]> bez otwarcia sekcji, innymi słowy zapis <a>tekst]]></a> jest błędny. Sekcja ta może być także przydatna, gdy w ramach XML’a chcemy osadzić kod HTML, który nie będzie wtedy parsowany jako XML i można zachować kod w oryginalnej postaci (tzn. encji) Przykład takiej sekcji:
<a><![CDATA[5 < 6 & 2 < 3]]></a>.
Przejdę do kolejnej istotnej kwestii tj. deklaracji XML. W3C zaleca, aby każdy dokument XML na samym początku (nie może być nic przed nią, nawet komentarz !) zawierał deklarację XML w postaci np.:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
przy czym tutaj wyjątkowo kolejność atrybutów jest istotna. I tak:
- atrybut version jest wymagany, obecnie dopuszczalne wartości to 1.0 i 1.1, choć 1.1 się raczej nie używa
- encoding jest opcjonalne, jest to dodatkowa informacja dla parsera jakiego kodowanie użyliśmy, wielkość liter bez znaczenia
- standalone jest także opcjonalne, dopuszczalne wartości to yes (gdy XML nie jest podpięty do zewnętrznego DTD) i no (jest podpięty). W praktyce nie stosowane, parser i tak sobie poradzi bez tego.
W XML’u można umieścić komentarz np.:
<!--to jest komentarz-->
nie można w środku komentarza umieścić −− np.:
<!--to--jest komentarz-->
jest błędne, nie można także zamykać np. przez −−−> , zagnieżdżać komentarzy, a także m.in: umieszczać ich w środku znacznika oraz wartości atrybutów. Natomiast można je umieszczać w zawartości elementu, choć jest to mało powszechna praktyka.
To już prawie wszystko, zostały jeszcze instrukcje przetwarzania (ang. processing instruction, PI), które umieszcza się wewnątrz elementu głównego. Zatem wbrew temu, co niektórzy twierdzą deklaracja XML nie jest PI. Te instrukcje mogą wydawać czymś dziwnym, ale osoby znające np. PHP wiedzą, że w (X)HTML’u możliwość umieszczenia kodu skryptowego np.:
<?php echo "<php-output>Witaj w PHP. Dzisiejsza data to ".date("d-m-Y").".</php-output>"; ?>
Dokładnie tak samo wygląda PI, jest ograniczony przez specjalne znaczniki <? i ?>, tuż po tym pierwszym podaje się nazwę procesora przetwarzającego, nazwa podlega tym samym ograniczeniom co nazwa elementu i jest to tzw. PITarget potem podaje się treść (ciało) PI i na końcu zamyka przez ?>. PI należy stosować tylko wtedy, kiedy jest to rzeczywiście potrzebne.
Powyższe zasady precyzują jak tworzyć poprawne XML, trzeba pamiętać, że takie zwroty jak PCDATA zostały „w spadku” po SGML’u, który był standardem o dużych możliwościach, ale nieco zbyt skomplikowanym. Celem opracowania XML’a było maksymalnie uproszczenie składni i zasad SGML’a. Należy też pamiętać, że rekomendacja W3C owszem określa wszelkie zasady budowy poprawnego XML’a, ale w praktyce reguły gry ustala procesor XML (np. Apache Xerces-J 2.6.2 jest domyślnym parserem dla Javy zawartym w JDK6).
Przestrzenie nazw XML
Jest to opcjonalny mechanizm, który pozwala przydzielić elementy do umownego „worka z nazwami”. Opcjonalny, gdyż z przestrzeni nie trzeba korzystać, dowodem na to jest wcześniejszy (i poniższy) przykład, w którym elementy nie są przypisane do żadnej przestrzeni. W tym miejscu trzeba mocno podkreślić, że przestrzenie nazw są czymś zupełnie innym od mechanizmów walidacji takich jak DTD/XSD/RELAX NG/XDR, nie zmienia to jednak faktu, że obie techniki mogą być komplementarne względem siebie (podobnie jak cały stos technologii rodziny XML). Zasadniczo przestrzenie nazw powstały po to żeby dało się wyróżnić, określić dane słownictwo i móc w ramach jednego dokumentu XML komponować wiele słownictw tak, żeby dało się je łatwo rozróżnić unikając dublowania nazw elementów (trochę podobny mechanizm jest w Javie, gdzie klasy są organizowane w wielopoziomowe pakiety, klasy mogą mieć identyczne nazwy, ale jeśli należą do różnych pakietów, to nie ma problemu z ich rozróżnieniem). Weźmy taki (nieco abstrakcyjny) przykład:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book>
<title>Thinking in Java</title>
</book>
<html>
<head><title>Thinking in Java webpage</title></head>
<body><p>Welcome</p></body>
</html>
</books>
Bardziej praktycznie byłoby pokazać kod XSLT (tam zastosowanie przestrzeni jest niezbędne), ale wybrałem prostszy, żeby pokazać samą zasadę działania. Przestrzenie nazw są mechanizmem, który pozwala łatwo określić do jakiego słownictwa należą dane elementy (wraz z przypisanymi do moch atrybutami). Powyższy XML jest jak najbardziej well-formed, ale nie pozwala „koncepcyjnie” określić czy element head należy do książki, czy do html’a, trzeba skądś wiedzieć, że tylko ten head, który jest potomkiem elementu html „koncepcyjnie” należy do zbioru nazw związanych z html’em. A teraz ten sam przykład z użyciem przestrzeni nazw:
<?xml version="1.0" encoding="UTF-8"?>
<myBooks:books xmlns:myBooks="http://mars.iti.pk.edu.pl/~mfi/books">
<myBooks:book>
<myBooks:title>Thinking in Java</myBooks:title>
</myBooks:book>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Thinking in Java webpage</title></head>
<body><p>Welcome</p></body>
</html>
</myBooks:books>
Powyższy przykład jest także semantycznie zgodny z:
<?xml version="1.0" encoding="UTF-8"?>
<books xmlns="http://mars.iti.pk.edu.pl/~mfi/books">
<book>
<title>Thinking in Java</title>
</book>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Thinking in Java webpage</title></head>
<body><p>Welcome</p></body>
</html>
</books>
oraz także:
<?xml version="1.0" encoding="UTF-8"?>
<myBooks:books xmlns:myBooks="http://mars.iti.pk.edu.pl/~mfi/books">
<myBooks:book>
<myBooks:title>Thinking in Java</myBooks:title>
</myBooks:book>
<html:html xmlns:html="http://www.w3.org/1999/xhtml">
<html:head><html:title>Thinking in Java webpage</html:title></html:head>
<html:body><html:p>Welcome</html:p></html:body>
</html:html>
</myBooks:books>
a nawet:
<?xml version="1.0" encoding="UTF-8"?>
<myBooks:books xmlns:myBooks="http://mars.iti.pk.edu.pl/~mfi/books"
xmlns="http://www.w3.org/1999/xhtml">
<myBooks:book>
<myBooks:title>Thinking in Java</myBooks:title>
</myBooks:book>
<html>
<head><title>Thinking in Java webpage</title></head>
<body><p>Welcome</p></body>
</html>
</myBooks:books>
Znaczeniowo wszystkie te zapisy są identyczne, to raczej kwestia stylu, który będzie się stosowało. Przestrzeń nazw określa się przez dodanie specjalnego atrybutu do elementu głównego słownictwa (ew. do elementu głównego dokumentu jak w ostatnim przykładzie). Można to zrobić na dwa sposoby:
- przez określenie prefiksu np. xmlns:myBooks=”http://mars.iti.pk.edu.pl/~mfi/books”. Wszystkie elementy, w których dodany zostanie ten prefiks będą należy do zadanej przestrzeni (jeśli nie mają prefiksu, to nie będą należały do tej przestrzeni). Na element zapisany w postaci prefiks:nazwa mówi się czasem QName (od ang. qualified name).
- bez określenia prefiksu np. xmlns=”http://mars.iti.pk.edu.pl/~mfi/books”, wtedy wszystkie elementy podrzędne wraz z tym na którym określono przestrzeń, aby na elemencie podrzędnym uciec od tej przestrzeni można zastosować konstrukcję <a xmlns=”"></a> (wtedy elementy podrzędne od a wraz nim samym nie będą należały do żadnej przestrzeni. Ten sposób jest także zwany nadawaniem domyślnej przestrzeni nazw.
Prefiks podlega tym samym ograniczeniom co nazwa elementu (nie może zaczynać się od cyfry itd.). Dla danego elementu można ustalić tylko jedną przestrzeń domyślną. A teraz przejdźmy wartości atrybuty xmlns (od XML namespace), w przykładach umieściłem m.in. http://mars.iti.pk.edu.pl/~mfi/books, jest do de facto nazwa mojej nowo utworzonej przestrzeni nazw. Tak jest, prefiks można wstawić w różnych XML’ach zupełnie dowolny (choć do dobrej praktyki należy trzymanie się jednego jak np. xs w XML Schema). Adres URL gwarantuje, że ta przestrzeń będzie unikatowa w skali globu, nikt inny raczej nie przestrzeni o takiej nazwie. Formalnie nazwą przestrzeni może być wartość URI (ang. Uniform Resource Identifier), czyli identyfikator dowolnego zasobu. Jako, że w sieci można znaleźć kilka błędnych opisów napiszę wyraźnie, że URI może występować tylko w dwóch osobnych postaciach:
- URL (ang. Uniform Resource Locator), czyli lokalizacja zasobu (jak dostać się do zasobu ?)
- URN (ang. Uniform Resource Name), czyli unikalna nazwa zasobu (w formacie urn:NID:NSS, raczej rzadko stosowane)
Kilka przykładów URL’i:
https://www.example.com?id=5&fwx#top http://149.156.146.210:80/~mfi/ mailto:admin@example.com?subject=help file:///C:/image.png schemas/books.dtd (ścieżka relatywna, względna od bieżącego kontekstu)
Każdy URL jest jednocześnie URI, ale nie na odwrót np. urn:isbn:83-7366-130-1 jest to prawidłowy URI (a konkretnie URN), ale w żadnym razie nie jest to URL. URL niekoniecznie musi być adresem strony WWW otwieranej w przeglądarce, ale tak najczęściej bywa.
Najczęściej nazwa przestrzeni jest adresem http (nigdy się nie spotkałem żeby było inaczej), ale co ważne adres ten nie musi prowadzić do niczego konkretnego, może być to nawet nieistniejąca strona i jest to całkowicie prawidłowe. W3C nie określa co powinno się tam znaleźć (powstał do tego projekt RDDL niezwiązany z W3C, który jednak powszechnie się nie przyjął). Ponadto nie istnieje rejestr oficjalnych przestrzeni nazw, owszem istnieje pewna grupa „dobrze znanych” jak np.:
| URL przestrzeni nazw | Aplikacja XML |
|---|---|
| http://www.w3.org/1999/xhtml | XHTML |
| http://www.w3.org/2001/XMLSchema | XML Schema (XSD) |
| http://relaxng.org/ns/structure/1.0 | RELAX NG |
| http://www.w3.org/1999/XSL/Transform | XSLT |
| http://www.w3.org/2000/svg | SVG |
| http://www.w3.org/1998/Math/MathML | MathML |
ale właściwie żadna nadrzędna organizacja ich nie kontroluje (oznacza to tyle, że każdy może utworzyć swoją własną przestrzeń).
Środowisko do technologii XML
Początkowo do edycji prostych dokumentów powinien wystarczyć zwykły edytor, ale wraz z poznaniem kolejnych technologii warto zaopatrzyć się w dedykowane środowisko IDE do XML’a, które znacząco ułatwia pracę i czyni ją znacznie bardziej efektywną. Wśród profesjonalnych, kompleksowych narzędzi godne polecenia są:
- oXygen XML Editor (możliwość integracji z Eclipse)
- Altova XMLSpy (możliwość integracji z Visual Studio oraz Eclipse)
Trudno jednoznacznie określić, które z tych dwóch środowisk jest lepsze, pewne jest, że Altova jest „nieco” droższa (m.in. daje wsparcie dla XBRL, ang. Extensible Business Reporting Language i lepiej radzi sobie z dużym plikami). Nie zmienia to faktu, że obydwa są wspaniałe (jednak Altova może być bardziej korzystna dla systemów opartych o .NET). Oba programy można bezpłatnie testować przez 30 dni (pełne wersje trial).
Jeśli korzystasz z systemu Windows, a nie zamierzasz wydawać ani złotówki, to do eksperymentów z DTD/XSD/XPath/XSLT (wraz z 2.0) i XQuery 1.0 godny polecenia może być Notepad++ oraz darmowy silnik AltovaXML (obsługa z linii komend), lub Saxon-HE (ten wymaga Java’y, ale „za to” jest multiplatformowy).
W czasie opracowywania tego artykułu korzystałem z książki „Beginning XML, 4th Edition” wyd. Wrox i rekomendacji W3C. Możesz także skorzystać z materiałów kursu online XML na stronie W3Schools.


(2 głosów, średnia: 4,00 / 5)



Zostaw odpowiedź