It won’t be a stretch to bet that you’ve heard of XML. The infamous markup format was intended to be easily parseable by machines, in addition to being readable by humans. Needless to say, it failed to deliver on either of these promises. Markup elements tend to obscure the actual data, while parsing it – with all its namespaces, !DOCTYPE
s and ![CDATA[
s – is convoluted and not exactly efficient.
Other formats have thus risen to popularity, out of which JSON is probably widest known and used. It also has excellent support on many platforms.
For the purpose of transporting data between Internet endpoints, or for various APIs offered by websites and services, it works pretty great. There are other applications, though, where it might be the obvious first choice – but not necessarily the best one.
What JSON does well is ease to read and parse: the syntax can be outlined and defined in few paragraphs. However, at the same it’s not that convenient to write.
Unlike actual JavaScript, it needs quotes around keynames, even if they would pass as identifiers. (And by quotes I mean double-quotes, also where apostrophes would be better). Furthermore, it requires keeping track of separators between key-value pairs or array elements, not allowing to have a handy trailing comma at the end.
And lastly, there is no good support for longer texts due to lack of multi-line string literals.
There is another, lesser known format which addresses these concerns very well. It’s called YAML, recursively from YAML Ain’t Markup Language. Here’s a short sample:
At first sight it probably appears as pythonic (or haskellish) counterpart to the C-like JSON. Indentation does indeed matter, at least in the most popular and powerful variant of YAML syntax.
However, giving this bit of significance to whitespace allows to substantially reduce syntactic clutter. There are no curly or square brackets, and no commas. For the most part, there’s not much use for quotes either: strings are easily recognized as both keys and values, even if they contain spaces. Arrays are also supported in a straightforward way: by listing their elements with a leading dash (-
), including cases where they are key-value objects themselves.
There’s even support for long strings that span multiple lines:
Here, pipe character (|
) instructs parsers to preserve newlines and most of the whitespace, excluding the leading indent. Were it replaced with greater-than sign (>
), an HTML-like fold would be performed, converting chains of whitespace into a single space.
Simple YAML documents represent a tree of keys and values which is much the same as the one produced from JSON files. For some programming languages, this similarity extends to the parsing libraries, as they offer more or less the same interface:
Even if it’s not the case for your language, it’s quite likely there is a YAML parser readily available.
Funny thing about YAML is that its glaringly simple syntax hides very powerful and flexible format.
For example, the values are actually typed. They can be strings or null
s, but also integers, floats or booleans. Syntactic rules make a very good job here at automatically detecting the types; for instance, the word Yes
will be recognized as boolean truth if standing on its own, but a text starting with it will be correctly recognized as string.
The other nifty feature is referencing. Parts of YAML document tree can be given labels, while other parts can later use those labels to point back to specific nodes. The whole structure can therefore morph into something more general than just a tree:
With types (incl. custom ones) and references, YAML can actually serve pretty well as serialization format for persisting objects.
But besides that, what YAML is actually good for?
I have hinted in the beginning that it seems like a decent choice for structured text data which is meant to be hand-edited. Various configuration files fall into this category, as well as some datasets around the size of contact list. I used YAML as config format for my IRC bot and it worked very well for this purpose. I’m also using it to store initialization data for database used by another side project of mine.
So, if you are not exercising YAML in any of your current endeavors, I’m encouraging you to give it a try. It might not be the best thing since sliced bread, but it’s very pleasant format to work with.
XML kojarzy się raczej z technologiami webowymi i językami, które się z nimi wiążą – jak C#, Java, Ruby, itp. Nie zapominajmy jednak, że jest to także pewien format zapisu informacji. Ma on swoje wady (duży rozmiar), ale również zalety – jak np. możliwość edycji dowolnym edytorem tekstu – które mogą być pożyteczne w wielu zastosowaniach. Także wtedy, gdy piszemy w C++.
Oczywiście stworzenie własnego parsera XML nie jest bardzo trudne – mogę to powiedzieć z czystym sumieniem, gdyż samemu zdarzyło mi się takie dzieła (o różnym stopniu skomplikowania i funkcjonalności) popełnić w ilości co najmniej dwóch :) Nie jest to jednak zajęcia specjalnie kreatywne. Są też dla niego alternatywy i właśnie o jednej z nich – bibliotece dla C++ przeznaczonej do obsługi XML-a – chciałbym dzisiaj napisać.
Nazywa się ona TinyXML i jest to nazwa nadzwyczaj trafna. Jest to bowiem mały (ok. kilka tysięcy linii) i zgrabny kawałek kodu, który pozwala operować na dokumentach XML zarówno sensie odczytu, jak i zapisu. Rozprowadzany jest on na licencji ZLib, pozwalającej na używanie w produktach komercyjnych i niekomercyjnych. A ponieważ składa się na niego tylko kilka plików .cpp, łatwo korzystać z niego w projektach albo nawet dołączyć do własnego frameworka czy engine‘u.
A korzystać z TinyXML warto. Wśród istotnych cech tej biblioteki można wymienić to, że:
<!DOCTYPE>
(czyli z czymś, czego nikt normalny już nie używa ;-))Nie mniej ważne jest to, że biblioteka TinyXML jest prosta w obsłudze. Jeśli mieliśmy coś wspólnego z przetwarzaniem XML w innych językach programowania, nie powinna nam ona sprawić żadnego kłopotu. Nie ma w niej naturalnie żadnych zaawansowanych feature‘ów w rodzaju zapytań XPath, transformacji XSL czy walidacji w oparciu o XML Schema, bo nie do takich zastosowań została ona stworzona. Jeżeli jednak nie potrzebujemy takiej zaawansowanej funkcjonalności, a chcemy jedynie np. odczytywać i zapisywać XML-owe pliki konfiguracyjne, stworzyć klienta RSS czy wykonywać tysiące innych pożytecznych, a nieskomplikowanych operacji na znacznikowym formacie danych, to TinyXML jest całkiem dobrym wyborem.
No, chyba że bardzo lubimy samodzielne pisanie parserów ;)
Myślę, że większość programistów miała przynajmniej przelotny kontakt z wyrażeniami regularnymi. Zwykle używa się do bardziej zaawansowanego wyszukiwania podciągów w tekście – nie określonych sekwencji liter, ale fragmentów określonych raczej pewnymi warunkami. Innym ich zastosowaniem jest też sprawdzanie, czy podany łańcuch pasuje do pewnego określonego formatu. Przy pomocy poniższego wyrażenia:
można na przykład sprawdzić poprawność adresu e-mail (czy zawiera on znaczek @, czy nazwa domeny jest przynajmniej formalnie poprawna, itd.). Nietrudno zauważyć jednak, że sama postać wyrażenia jest dość odstręczająca, a poza tym sporo elementów się w nim powtarza – choćby sekwencja dopasowująca pojedynczy znak alfanumeryczny. Poza tym dokładna składnia wyrażeń w danej bibliotece może być niekiedy specyficzna, chociaż podstawy (czyli np. elementy pokazane powyżej) powinny być w zasadzie wszędzie takie same.
Mimo to czasem warto użyć tego narzędzia również w bardziej zaawansowanym celu: parsowania ciągów znaków w celu wydzielenia i odczytania z nich określonych fragmentów. Zapewne nie da się w ten sposób przetworzyć na przykład dokumentu XML czy innego skomplikowanego formatu, lecz w prostszych przypadkach może się to okazać szybsze i wygodniejsze. Alternatywą jest oczywiście samodzielne napisanie parsera, tokenizera czy innego tego typu obleśnego automatu stanów :)