Main | Lost and found »

Delle strutture arboree, e di come ci siano piu` cose in CPAN di quante un programmatore ne possa immaginare

pruning.gif

"Naturalmente, un file di log''

Dovevo sospettarlo. Bisogna stare attenti quando si incontra valdez su #nordest.pm. E` tipo un Gremlin: assolutamente non bisogna dargli retta dopo mezzanotte. Si`, perche` solitamente avra` l'esecrabile progetto di darvi delle idee, e si sa come va a finire poi in questi casi.

L'altra notte, in particolare, si discuteva di file-system: valdez avanzava l'idea che un file-system non dovesse essere necessariamente manipolato come un albero. Optando per un altro tipo di struttura, sarebbe possibile ottenere informazioni in maniera piu` efficiente.

Per quanto mi riguarda, non ero tanto sicuro di aver capito dove valdez volesse andare a parare (e` il tipico caso in cui sarebbe molto meglio discutere de visu con un pezzo di carta davanti...) ma poco dopo ho ribaltato dialetticamente la questione: siamo sicuri che non sia possibile applicare la metafora del file-system a qualcosa che non sia un disco pieno di file?

Bene o male dentro ad un filesystem ci sguazziamo tutti da anni, ed e` (o e` diventato, ma in questo caso e` lo stesso) una delle maniere piu` naturali per manipolare oggetti organizzati gerarchicamente.

Ora, si da` il caso che io usi sempre piu` spesso il formato XML per gestire le mie piccole collezioni di informazioni. I motivi sono di diverso ordine:

  • XML e` un formato "liquido" (passatemi il termine). Da un file XML posso ottenere qualunque altra cosa, e il Perl dispone di una vasta gamma di tool per operare questa manipolazione. Ad esempio la routine di creazione delle pagine della bibliografia di perlmongers.it e` fatta cosi`, usando il Template Toolkit piu` XML::Simple:
            [% USE xml = XML.Simple( './cat.xml' ) %]
              [% FOREACH b = xml.book %]
                      [% FILTER redirect("${b.key}.html") %]
                              [% INCLUDE 'header.tt2' %]
                              [%# E qui ancora un po' di HTML %]
                      [% END %]
              [% END %]

Tale ricchezza di tool e` presente anche in altri linguaggi (non so in che misura, immagino in maniera robusta). Affidandomi a XML sono quindi a posto anche se dovessi ricevere un'illuminazione (o un colpo in testa, a seconda).

  • Un file XML e` comunque un file di testo. Il che vuol dire che anche in condizioni di penuria dei detti tool potrei accedere alle informazioni (benche` con un braccio legato dietro alla schiena e metaforicamente orbo, certo). E` lo stesso motivo per cui non uso piu` Word per i testi, ad esempio, ma mi sono sottoposto a quel periodo di penitenza necessario ad imparare un po' di LaTeX.

Pensando a quello che mi aveva detto valdez, mi e` venuto in mente che probabilmente non era una cattiva idea trattare documenti XML come fossero un file system. Il nome di moduli come XML::XPath pareva se non altro suggerire che non era un'idea troppo balzana.

Per intenderci, pensavo di scrivere qualcosa che consentisse sessioni di questo genere:

 dummy_xmlcli> mount bookmarks.xml
  Loading bookmarks.xml...OK
  dummy_xmlcli> ls
  
  <bookmarks></bookmarks>
 dummy_xmlcli> cd bookmarks
  dummy_xmlcli> ls 
  <folder name="Perl"></folder>
  <folder name="People"></folder>
  <folder name="Math"></folder>
 dummy_xmlcli> cd folder[name="Perl"]
  dummy_xmlcli> ls
  <bookmark url="http://www.perl.com"></bookmark>
  <bookmark url="http://www.perlmonks.org"></bookmark>
  <bookmark url="http://www.perlmongers.it"></bookmark>
 dummy_xmlcli> mkdir bookmark[url="http://www.perlmongers.it"]
  dummy_xmlcli> mkdir bookmark[url="http://www.perlmongers.it"]/description
  dummy_xmlcli> vim bookmark[url="http://www.perlmongers.it"]/description
   [...]
  dummy_xmlcli> unmount bookmarks.xml
  bookmarks.xml has been modified. Do you want to save it? (y/n)
  Saved. Good bye!

E cosi` via... Ho anche cominciato a scrivere un po' di codice (con Term::ReadLine e XML::XPath si fa abbastanza presto). In realta` non tutto quello che avevo ipotizzato mi sembrava buono. Ad esempio il parallelo tra mkdir e l'inserimento di un nuovo elemento mi pare un po' forzato. Inoltre ci sono cose che non ho delineato nell'esempio e che mi sarebbe piaciuto implementare: ad esempio la possibilita` di lavorare su piu` volumi (ovvero su piu` file xml contemporaneamente). Quindi copiare e muovere insiemi di elementi usando le wildcard oppure espressioni regolari come selettori (e l'aderenza allo schema come viene gestita?).

Insomma, stavo pensando a tutte queste cose quando ho scoperto, girovagando per Internet, che uno strumento del genere esiste gia`. Si chiama XML::XSH. Dopotutto non era un'idea tanto balzana, a quanto pare.

XML::XSH

Il componente piu` interessante che viene installato insieme a XML::XSH e` xsh. Da una shell "vera", basta digitare xsh -i

 [alice:~] larsen% xsh -i
  ---------------------------------------------------------
   xsh - XML Editing Shell version 1.5/0.9 (Revision: 1.8)
   ---------------------------------------------------------
   Copyright (c) 2002 Petr Pajas.
   This is free software, you may use it and distribute it under
   either the GNU GPL Version 2, or under the Perl Artistic License.
   Using terminal type: Term::ReadLine::Stub
   Hint: Type `help' or `help | less' to get more help.
   xsh scratch:/>

E da questo momento si puo` cominciare a pestare tasti per creare e manipolare file XML. Provo a creare un file con una lista di bookmark organizzati in cartelle. Per prima cosa bisogna creare un nuovo documento, assegnargli un identificatore e fornire un'espressione che costituira` la radice del documento.

 xsh scratch:/> create bookmarks "<bookmarks />"
  xsh bookmarks:/>

Ora procedo creando un po' di elementi folder, caratterizzati da un attributo name:

 xsh bookmarks:/> cd bookmarks
  xsh bookmarks:/bookmarks> add element "<folder name='Perl'>" into .
  xsh bookmarks:/bookmarks> add element "<folder name='Math'>" into .
  xsh bookmarks:/bookmarks> add element "<folder name='People'>" into .
  xsh bookmarks:/bookmarks> ls
  <bookmarks><folder name="Perl"/>
      <folder name="Math"/><folder name="People"/></bookmarks>
  Found 1 node(s).
  xsh bookmarks:/bookmarks>

All'interno dei quali inserisco i bookmark veri e propri.

 xsh bookmarks:/bookmarks> add element 
    "<bookmark url='http://www.perlmongers.it'>" 
    into ./folder[1]
  xsh bookmarks:/bookmarks> add element+ 
    "<bookmark url='http://larsen.perlmonk.org'>"+ 
    into ./folder[3]
  xsh bookmarks:/bookmarks> ls
  <bookmarks><folder name="Perl">...</folder><folder name="Math"/>
    <folder name="People">...</folder></bookmarks>
  Found 1 node(s).
  xsh bookmarks:/bookmarks>

Notare che ho scritto un numero di fianco al nome dell'elemento per specificare all'interno di quale folder desideravo inserire il bookmark. In realta` si puo` specificare in vari modi il path sul quale operare, usando la sintassi di Xpath:

 xsh bookmarks:/bookmarks> add element+ 
    "<bookmark url='http://perl.plover.com'>"+ 
    into ./folder[@name='People']
  xsh bookmarks:/bookmarks> cd folder[3]
  xsh bookmarks:/bookmarks/folder[3]> ls
  <folder name="People"><bookmark url="http://larsen.perlmonk.org"/>
    <bookmark url="http://perl.plover.com"/></folder>
  Found 1 node(s).

Con xsh esiste ovviamente la possibilita` di caricare due documenti per copiare e muovere elementi. Supponendo che esista gia` un ulteriore file di bookmark chiamato bob_bookmarks.xml fatto cosi`:

 
  <bookmarks>
    <folder name="Perl">
      <bookmark url="http://www.perl.com"/>
    </folder>
    <folder name="Math"/>
    <folder name="People">
      <bookmark url="http://yetanother.org/damian"/>
      <bookmark url="http://dada.perl.it"/>
    </folder>
  </bookmarks>

Allora e` possibile:

 xsh bookmarks:/bookmarks> open bob=bookmarks_bob.xml
  parsing bookmarks_bob.xml
  done.
  xsh bob:/> files
  bob = bookmarks_bob.xml
  bookmarks = bookmarks_alice.xml
  scratch = new_document1.xml
  xsh bob:/>

(scrath e` il documento "vuoto" iniziale).

 xsh bob:/> cd bookmarks
  xsh bob:/bookmarks> xcopy folder[@name='People']/bookmark+ 
    into bookmarks:/bookmarks/folder[@name='People']
  xsh bob:/bookmarks> select bookmarks
  xsh bookmarks:/> cd bookmarks/folder[3]
  xsh bookmarks:/bookmarks/folder[3]> ls
    <folder name="People">
      <bookmark url="http://larsen.perlmonk.org"/>
      <bookmark url="http://perl.plover.com"/>
      <bookmark url="http://yetanother.org/damian"/>
      <bookmark url="http://dada.perl.it"/></folder>
    Found 1 node(s).

Completate tutte queste operazioni, si salva il documento in un file:

 xsh bookmarks:/bookmarks> saveas bookmarks bookmarks_alice.xml
  bookmarks=bookmarks_alice.xml --> bookmarks_alice.xml (utf-8)
  saved bookmarks=bookmarks_alice.xml as+ 
    bookmarks_alice.xml in utf-8 encoding
  xsh bookmarks:/bookmarks>

In realta` xsh e` molto piu` potente. Ad esempio non ho parlato dei suoi costrutti foreach, while e map, analoghi a quelli presenti in Perl, o della possibilita` di usare variabili. Se si vuole e` possibile scrivere programmi cosi` come si scrivono script di shell, ma secondo me oltre un certo punto conviene usare il Perl, piu` familiare e piu` potente. Tanto piu` che si puo` usare XML::XSH anche all'interno di un programma scritto in Perl.

 use XML::XSH;
  xsh << SCRIPT;
  ... qualcosa di interessante ...
  SCRIPT

Ma xsh rimane un ottimo tool da combattimento, quando non si vuole spendere tempo a decidere quale tra i tanti moduli della gerarchia XML:: vada bene per l'esigenza momentanea.

TrackBack

TrackBack URL for this entry:
http://larsen.perlmonk.org/cgi/mt/mt-tb.cgi/3

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)