Guido Socher (homepage)
Yazar hakkında:
Oldukça esnek ve hızlı bir betik yazım dili olması sebebi ile Guido Perl'den hoşlanmaktadır.
Perl'ün açıkkod ile yürüdüğünüzde tanıdığı imkanları ve özgürlüğü ifade eden "Bunu yapmak için birden fazla
yolumuz var" sloganını sever.
Türkçe'ye çeviri:
İnanç Özçubukçu <inanco(at)atlas.net.tr>
İçerik:
|
Managing HTML with Perl, HTML::TagReader
Özet:
Eğer 10 HTML sayfasından fazla bir sanal yöreyi idare etmek isterseniz size destek amaçlı bazı yazılımlara ihtiyaç
olduğunu göreceksiniz.
Birçok alışılagelmiş yazılım dosyaları satır satır (karakter karakter) okur. Maalesef satırların SGML/XML/HTML
dosyalarında bir anlamı yoktur. SGML/XML/HTML dosyaları Etiket tabanlıdır. HTML::TagReader bir dosyayı Etiket ile işletmek için bir
bileşendir.
Bu yazı Perl'ü biraz bildiğinizi varsaymaktadır. Eğer Perl öğrenmek istiyorsanız my Perl tutorials
(January 2000) adresine bir göz atın.
_________________ _________________ _________________
|
Giriş
Alışıla gelmiş dosyalar satır temellidir. Örnek olarak Unix'teki /etc/hosts, /etc/passwd tanımlama dosyaları gibi.
Satır satır veri girmek ve düzeltmek için fonksiyonlarınızın olduğu daha da eski işletim sistemleri vardır.
SGML/XML/HTML
dosyaları Etiket temellidir. Burada satırların bir anlamı yoktur ama yine de dosya editörleri ve insanlar halen bir şekilde
satır tabanlıdırlar.
Özellikle büyük HTML dosyaları genelde bir dizi HTML kodu içeren satırlardan oluşur. "Tidy" gibi bazı araçlar html'yi
yorumlatıp okunabilir yaparlar. Biz HTML dahi olsa satırlar yerine Etiket kullanmaktayız. Bunu C-kodu ile mukayese edebilirsiniz.
Teorik olarak tüm kodu basit bir satırda yazabilirsiniz. Kimse bunu yapmaz. Yoksa okunamaz olur.
Bu sebeple bir HTML yazım denetçisinin "ERROR after tag 4123" yazmasından çok "ERROR: line ..." yazmasını beklersiniz.
Bunun sebebi yazım aracınızın belirtilen satıra kolaylıkla atlayabilmesidir.
Burada ihtiyaç olan güzel ve kolay bir yolla HTML dosyasını Etiket Etiket olarak işlemek ve halen satır numaralarını
tutmaktır..
Muhtemel bir çözüm
Bir dosyayı Perl'de okumanın en alışılmış yolu while(<FILEHANDLE>) işletimcisi kullanmaktır. Bu veriyi
satır satır okuyacak ve her satırı $_ değişkenine aktaracaktır. Perl neden bunu yapıyor? Perl, "\n" satır sonunu ifade eden
içe yönelik INPUT_RECORD_SEPARATOR olarak adlandırılan bir değişkene sahiptir. Eğer $/=">" olarak atarsanız Perl ">"
'ı "satır sonu" gibi kullanacaktır. Aşağıdaki komut satırı Perl betiği sonunda hep ">" olacak şekilde html dosyasını
yeniden biçimlendirecektir :
perl -ne 'sub BEGIN{$/=">";} s/\s+/ /g; print
"$_\n";' file.html
Bir HTML dosyası şuna benzer
<html><p>some text here</p></html>
will become
<html>
<p>
some text here</p>
</html>
Önemli olan yine de okunulabilirlik değildir. Yazılım geliştirici için önemli olan verinin kodundaki fonksiyonlarından
Etiket Etiket geçmesidir. Bununla birlikte asıl HTML ayrı satırlarda "a" ve "href" içerse bile bir "<a href= ..." aramak kolay
olacak.
"$/" (INPUT_RECORD_SEPARATOR) 'ı değiştirmek işlemde artışa sebep olmaz ve oldukça hızlıdır. Yine aynı şekilde
karşılaştırma işletimcisini ve alışılmış deyimleri bir seri gibi kullanmak ve dosyayı alışılmış deyimlerle işlemek mümkündür.
Bu biraz daha karmaşık ve yavaş olmakla birlikte sıklıkla kullanılmaktadır.
Sorun nerede?? Bu yazının başlığı dedi ki HTML::TagReader fakat ben sürekli ilave modüller gerektirmeyen daha
basit çözümlerden bahsediyorum. Bu çözümde yanlış olan bir şeyler olmalı:
- Genelde dünyadaki tüm HTML dosyaları hatalıdır. Örnek olarak C kod örnekleri barındıran ve HTML seviyesinde
şu şekilde görünen milyonlarca sayfa vardır
if ( limit > 3) ....
instead of
if ( limit > 3) ....
HTML'de "<" bir Etiket başlamalı ve">" bitmeli. Hiçbiri dosyanın bir yerinde kendisini belli etmemelidir. Çoğu
tarayıcı tümünü doğru gösterir ve hatayı gizler.
- "$/" değiştirmek tüm programı etkiler. Eğer HTML dosyasını okurken bir diğer dosyayı satır satır işletmek isterseniz
sorununuz var demektir.
Diğer bir deyişle "$/" (INPUT_RECORD_SEPARATOR) kullanmak sadece özel durumlarda mümkündür.
Elimde neyi
tartıştığımızı gösterir çok yararlı bir örnek program var. Her ne kadar "$/"ı "<"ye atasa da web tarayıcıları yanlış
konmuş "<" yi ">" gibi destekleyemez. Bu sebeple ">" yerine yanlış "<" yerleştirilmiş web sayfası daha azdır.
Program tr_tagcontentgrep(click to view) olarak adlandırılmakta
ve satır numarasının kaydının nasıl tutulduğunu da kod içerisinde görebilirsiniz. tr_tagcontentgrep, Etiket birçok satırdan
oluşuyor olsa bile, bir dizi (ör: "img") "grep" etmek için kullanılabilir. Şuna benzer:
tr_tagcontentgrep -l img file.html
index.html:53: <IMG src="../images/transpix.gif" alt="">
index.html:257: <IMG SRC="../Logo.gif" width=128
height=53>
HTML::TagReader
HTML::TagReader iki sorunu INPUT_RECORD_SEPARATOR 'ı uyarlamakla çözümler ve aynı zamanda düz yazıları Etiket'lerden
ayırmak için çok daha hoş bir yol sunar. Yüklü bir HTML:Parser gibi ağır değildir ve html kodunu işletince size istediğiniz
şeyi sunar:Etiket Etiket okuma yöntemidir.
Bu kadar laf yeter. İşte nasıl kullanacağınız. Önce kodunuz içerisine modülü yüklemek için
use HTML::TagReader;
yazmalısınız.
Sonuçta
my $p=new HTML::TagReader "filename";
kullanarak "dosyaismi" dosyasını açarız ve $p içerisindeki
nesneyi getiririz. Bir sonraki Etiket'i almak için şimdi $p->gettag(0) veya $p->getbytoken(0) çağırabiliriz. getbytoken
Etiket'ler arasındaki düz yazıları verirken gettag sadece Etiket'leri döndürür (< ve > arasındaki iş) ve onun ne olduğunu size
söyler (Etiket veya düz yazı). Bu fonksiyonla html dosyalarını işletmek oldukça basittir. Aslen geniş bir sanal yöreyi yönetmektir.
Tüm yazım şekline man page of HTML::TagReader adresinden
erişilebilir.
Şimdi gerçek bir örnek program. Döküman numarasına göre döküman başlığı basmakta:
#!/usr/bin/perl -w
use strict;
use HTML::TagReader;
#
die "USAGE: htmltitle file.html [file2.html...]\n" unless($ARGV[0]);
my $printnow=0;
my ($tagOrText,$tagtype,$linenumber,$column);
#
for my $file (@ARGV){
my $p=new HTML::TagReader "$file";
# read the file with getbytoken:
while(($tagOrText,$tagtype,$linenumber,$column) = $p->getbytoken(0)){
if ($tagtype eq "title"){
$printnow=1;
print "${file}:${linenumber}:${column}: ";
next;
}
next unless($printnow);
if ($tagtype eq "/title" || $tagtype eq "/head" ){
$printnow=0;
print "\n";
next;
}
$tagOrText=~s/\s+/ /; #kill newline, double space and tabs
print $tagOrText;
}
}
# vim: set sw=4 ts=4 si et:
Nasıl çalışıyor?
<title> yada <Title> yada <TITLE> ($tagtype olarak "title"a eşit olarak döndüler)
bulduğumuz zaman $p->getbytoken(0) ile html dosyasını okuyoruz. Ardından basmaya başlamak için bir bayrak ($printnow)
atıyoruz ve ne zaman ki </title> bulduk, basmayı durduyoruz.
Programı şu şekilde kullanıyoruz:
htmltitle file.html somedir/index.html
file.html:4: the cool perl page
somedir/index.html:9: joe's homepage
Elbette tr_tagcontentgrep 'i aşağıdan HTML::TagReader ile uygulamak mümkün. Yazmak için biraz daha
kısa ve basit olarak:
#!/usr/bin/perl -w
use HTML::TagReader;
die "USAGE: taggrep.pl searchexpr file.html\n" unless ($ARGV[1]);
my $expression = shift;
my @tag;
for my $file (@ARGV){
my $p=new HTML::TagReader "$file";
while(@tag = $p->gettag(0)){
# $tag[0] is the tag (e.g <a href=...>)
# $tag[1]=linenumber $tag[2]=column
if ($tag[0]=~/$expression/io){
print "$file:$tag[1]:$tag[2]: $tag[0]\n";
}
}
}
Betik kısadır ve fazla hata kaldırmaz ancak öte yandan tamamen işlevseldir. "gif" değişkenini
yakalamak için yazılması gereken:
taggrep.pl gif file.html
file.html:135:15: <img src="images/2doc.gif" width=34
height=22>
file.html:140:1: <img src="images/tst.gif" height="164"
width="173">
Bir örnek daha? İşte tüm <font...> ve </font> Etiket'lerini html
kodundan ayıklayacak bir program. Bu font
Etiket'leri bazı zayıf grafik tabanlı tarayıcılar tarafından yoğun olarak kullanılmakta
ve farklı tarayıcılar ve ekran
boyutları ile görüntülenmeye çalışıldıklarında sorun yaratmaktadırlar.
Bu basit sürüm tüm font Etiket'leri ayıklamakta.
Sadece font yüzü ve boyutunu ayarlamak ve rengi
değişmeden bırakmak için kullanabilirsiniz.
#!/usr/bin/perl -w
use strict;
use HTML::TagReader;
# strip all font tags from html code but leave the rest of the
# code un-changed.
die "USAGE: delfont file.html > newfile.html\n" unless ($ARGV[0]);
my $file = $ARGV[0];
my ($tagOrText,$tagtype,$linenumber,$column);
#
my $p=new HTML::TagReader "$file";
# read the file with getbytoken:
while(($tagOrText,$tagtype,$linenumber,$column) = $p->getbytoken(0)){
if ($tagtype eq "font" || $tagtype eq "/font"){
print STDERR "${file}:${linenumber}:${column}: deleting $tagtype\n";
next;
}
print $tagOrText;
}
# vim: set sw=4 ts=4 si et:
Gördüğünüz gibi sadece birkaç satırla kolayca kullanışlı programlar yazılabiliyor.
HTML::TagReader (örneklere bkz) paket kaynak kodu bazı HTML::TagReader uygulamalarını zaten içermektedir:
- tr_blck -- HTML sayfalarındaki kırık linkleri tarar
- tr_llnk -- HTML dosyaları içindeki linkleri listeler
- tr_xlnk -- dizinlerdeki linklerle index dosyaları genişletir
- tr_mvlnk -- perl komutları ile HTML dosyalarındaki etiketleri düzenler.
- tr_staticssi -- SSI direktiflerini genişletir #include sanal ve
#exec cmd ve statik bir html sayfası üretir.
- tr_imgaddsize -- <img 'ye width=... ve height=.. ilave eder.
src=...>
tr_xlnk ve tr_staticssi bir sanal yöreden CDRom yapmak istediğinizde çok kullanışlıdır. Bir sanal yöre sunucusu
http://www.linuxfocus.org yazdığınızda (index.html olmaksızın) size http://www.linuxfocus.org/index.html'yi verecektir.
Eğer ki tüm dosyaları ve dizinleri CD ye yazmış ve tarayıcınız aracılığı ile doğrudan CD ye erişiyorsanız (dosya:/mnt/cdrom)
bu durumda index.html yerine dizin listesi göreceksiniz ve bu işlem bir dizini gösteren her linki seçtiğinizde tekrarlanacaktır.
İlk LinuxFocusCD yi yapan şirket bu hatayı yaptı ve CD yi kullanım açısında bir felaket oldu. Şimdi veriyi tr_xlnk ile alıyorlar
ve CD ler çalışıyor.
Eminim ki HTML::TagReader 'ı kullanışlı bulacaksınız. Mutlu programlamalar!
References
Bu yazı için görüş bildiriminde bulunabilirsiniz
Her yazı kendi görüş bildirim sayfasına sahiptir. Bu sayfaya yorumlarınızı yazabilir ve diğer okuyucuların yorumlarına bakabilirsiniz.
<--, Bu sayının ana sayfasına gider
2003-10-10, generated by lfparser version 2.43