Presentation is loading. Please wait.

Presentation is loading. Please wait.

Mrežno računarstvo glava 8 HTML in Swing.

Similar presentations


Presentation on theme: "Mrežno računarstvo glava 8 HTML in Swing."— Presentation transcript:

1 Mrežno računarstvo glava 8 HTML in Swing

2 Uvodna priča Pokušaj pisanja koda koji čita HTML je bolno iskustvo.
Iako postoji HTML specifikacija niko je ne prati. A i sama specifikacija je problematična Imena elemenata mogu biti pisana velikim slovima, malim slovima ili mešovito vrednosti atributa mogu a ne moraju biti pod navodnicima ako jesu, mogu biti pod jednostrukim, a mogu i pod dvostrukim znak < može biti predstavljen sa < a može biti i < tag <P> se može koristiti i za početak ali i za kraj paragrafa zatvarajući </P>, </LI> i </TD> tagovi se mogu a ne moraju koristiti tagovi mogu da se preklapaju Ima previše načina da se uradi ista stvar da bi parsiranje HTML-a bilo jednostavan posao Zapravo, poteškoće otkrivene prilikom parsiranja HTML-a bile su jedna od primarnih motivacija za dosta striktniji XML u kome je precizno određeno šta je dopušteno, a šta ne i svim browser-ima je strogo zabranjeno da prihvataju dokumente koji ne prate standard. Kod HTML-a, suprotno, većina browser-a pokušava da ”popravi” loš HTML

3 Srećom, Sun obezbeđuje klase za osnovno parsiranje i prikazivanje HTML-a koje štite Java programera od većine muka rada sa neobrađenim HTML-om. paket javax.swing.text.html.parser može čitati HTML dokumente manje-više potpuno u njihovoj nestandardnoj grozoti  a paket javax.swing.text.html može renderovati osnovni HTML u JFC-zasnovanim aplikacijama

4 HTML na komponentama Većina tekstualnih Swing komponenti, poput labela, dugmadi, stavki menija, panoa sa tabovima i tool tip-ova dopušta da se tekst na njima zada kao HTML. Komponenta će prikazati HTML kako treba Ako želimo da labela na dugmetu uključi bold, italic ili plain tekst, najjednostavniji način je napisati labelu u HTML-u direktno u source kodu, npr. ovako: JButton jb = new JButton(”<html><b><i>Hello World! </i></b></html>”); Ista tehnika se može koristiti i za ostale nabrojane komponente

5 Primer1: HTML u JLabel aplet sa JLabel koja se prostire kroz više redova, a koristi HTML sa tim se može otići poprilično daleko skoro svi HTML tagovi su podržani, bar delimično, uključujući IMG i razne tagove za tabele jedini u potpunosti nepodržani HTML 3.2 tagovi su: <APPLET>, <PARAM>, <MAP>, <AREA>, <LINK>, <SCRIPT> i <STYLE>

6 Razni frame tagovi takođe nisu podržani (oni tehnički i nisu deo HTML 3.2)
dodatno, razni novi tagovi, uvedeni u HTML 4.0, poput BDO, BUTTON, LEGEND, TFOOT, nisu podržani Dalje, postoje neka ograničenja na druge uobičajene tagove. Prvo, relativni URL-ovi u atributima se ne razrešavaju jer za njih ne postoji stranica u odnosu na koju su relativni. Ovo najčešće utiče na SRC atribut taga IMG. Najjednostavniji način da se ovo prevaziđe jeste da se slike stave u istu JAR arhivu kao i aplet ili aplikacija i učitaju sa apsolutnog URL-a jar-a. Linkovi će se prikazivati kao plavi podvučeni tekst kao što je većina korisnika navikla, ali se ništa ne dešava kada se na njih klikne Forme se iscrtavaju, ali korisnik ne može u njih ništa da ukuca niti da uradi submit. Neka CSS level 1 svojstva kao što je font-size su podržana kroz atribut style, ali STYLE tag i eksterni stilski listovi nisu. Ukratko, HTML podrška je ograničena na statički tekst i slike. Na kraju krajeva, mi ovde samo pričamo o labelama, stavkama menija i drugim jednostavnim komponentama

7 JEditorPane Ako nam je potrebna interaktivnija, kompletna implementacija HTML 3.2, možemo koristiti javax.swing.JEditorPane Ova klasa obezbeđuje čak i kompletnije HTML 3.2 renderovanje koje može rukovati frejmovima, formama, hiperlinkovima i delovima CSS Level 1. JEditorPane takođe podržava plain tekst i osnovni RTF, mada je naglasak ovde na njenom korišćenju za prikaz HTML-a.

8 JEditorPane podržava HTML na prilično intuitivan način
Prosto se konstruktoru prosledi URL ili ogroman string koji sadrži HTML, a zatim prikaže kao i bilo koja druga komponenta postoje 4 konstruktora ove klase: public JEditorPane() public JEditorPane(URL initialPage) throws IOException public JEditorPane(String url) throws IOException public JEditorPane(String mimeType, String text) throws IOException

9 Podrazumevani konstruktor kreira JEditorPane bez inicijalnih podataka
Podrazumevani konstruktor kreira JEditorPane bez inicijalnih podataka. Ovo se kasnije može promeniti metodima setPage() i setText(): public void setPage(URL page) throws IOException public void setPage(String url) throws IOException public void setText(String html)

10 Primer 2: OReillyHomePage
koristi se podrazumevani konstruktor kako bi prikazao web stranu JEditorPane je smešten unutar JScrollPane kako bi se dobili scrollbar-ovi Swing korektno prikazuje stranice koje sadrže tabele, slike, linkove, boje, fontove i ostalo, bez gotovo imalo truda od strane programera. Ipak ima malo poteškoća sa širinama tabela. Uglavnom, što je strana osnovnija, to je Swing bolje prikazuje Ono što nedostaje je aktivnost! Linkovi jesu plavi i podvučeni, ali klik na jedan od njih ne menja prikazanu stranu. JavaScript i apleti se ne pokrecu. Shockvawe animacije i QuickTime filmovi ne rade. Password-protected web strane nisu dostupne jer nema načina da se obezbedi username i password. Možemo dodati sve ovo sami, ali to će zahtevati dodatni kod za prepoznavanje relevatnih delova HTML-a i odgovarajuće ponašanje. Različiti aktivni sadržaj zahteva različite nivoe podrške Podrška hipertekst linkovima, npr. je prilično pravolinijska, kao što ćemo videti kasnije ni dodavanje apleta nije tako teško. Uglavnom zahteva da se parsira HTML kako bi se pronašli tagovi i parametri i obezbedila instanca AppletContext interfejsa Dodavanje JavaScript-a je samo malo teže; treba neko da je već napisao JavaScript interpreter koji ćemo mi da koristimo. Srećom, Mozilla Project je napisao Open Source Rhino ( JavaScript interpreter koji možemo da koristimo. Apple-ov QuickTime za Javu ( – QuickTime podrška za Mac i Windows.

11 Drugi JEditorPane konstruktor prima URL objekat kao argument
Drugi JEditorPane konstruktor prima URL objekat kao argument. On se konektuje na zadati URL, download-uje stranu koju pronalazi i pokušava da je prikaže. Ako pokušaj ne uspe, izbacuje se IOException

12 primer (deo) JFrame f = new JFrame(”O’Reilly & Associates”); try{
URL u = new URL(” JEditorPane jep = new JEditorPane(u); jep.setEditable(false); JScrollPane scrollPane = new JScrollPane(jep); f.setContentPane(scrollPane); }catch(IOException ex){ f.getContentPane().add(new JLabel(”Could not load } f.setSize(512, 314); f.setVisible(true);

13 Treći JEditorPane konstruktor je skoro identičan drugom, osim što uzima String-formu URL-a umesto URL objekta kao argument. Jedan od IOException-a koji može izbaciti je MalformedURLException ako ne prepozna protokol. Inače, njegovo ponašanje je isto kao i ponašanje drugog konstruktora

14 primer (deo) try{ JEditorPane jep = new JEditorPane(” jep.setEditable(false); JScrollPane scrollPane = new JScrollPane(jep); f.setContentPane(scrollPane); }catch(IOException ex){ f.getContentPane().add( new JLabel(”Could not load } Nijedan od ovih konstruktora ne zahteva da zovemo setText() ili setPage(), pošto su te informacije već date konstruktoru. Ipak, ovi metodi se mogu zvati da bi se promenila prikazana strana ili tekst

15 Constructing HTML User Interfaces on the Fly
Četvrti JEditorPane konstruktor se ne konektuje na URL. On uzima podatke direktno iz drugog argumenta. MIME type podataka je određen prvim argumentom Npr. JEditorPane jep = new JEditorPane(”text/html”, ”<html><h1>Hello World! </h1> <h2>Goodbye World! </h2></html>”);

16 primer 3: Fibonačijev niz prikazan u HTML-u
Ovaj konstruktor može biti koristan kada želimo da prikažemo programski kreiran HTML ili da čitamo iz nekog drugog izvora umesto iz URL-a Program računa prvih 50 Fibonačijevih brojeva i zatim ih prikazuje kao HTML uređenu listu Značaj ovoga trebalo bi da je očigledan. Možemo koristiti blizak, lak za pisanje format za kreiranje korisničkog interfejsa koji koristi stilizovani tekst. Ovo je više nego adekvatno za preko 99% potreba za prikazom teksta, bez obzira da li su te potrebe prost izlaz iz programa, help fajlovi, izveštaji baza ili nešto kompleksnije

17 Rukovanje hiperlinkovima
Kada korisnik klikne na link u noneditable JEditorPane, pane ispaljuje HyperlinkEvent. Kao što možete pretpostaviti, na njega odgovara svaki od registrovanih HyperlinkListener objekata ovo je ista šema kao za AWT događaje javax.swing.event.HyperlinkListener interfejs definiše samo jedan metod, hyperlinkUpdate(): public void hyperlinkUpdate(HyperlinkEvent evt)

18 public HyperlinkEvent.EventType getEventType()
Unutar ovog metoda, smešta se kod koji odgovara na HyperlinkEvent. HyperlinkEvent objekat prosleđen metodu sadrži URL događaja, koji se može dobiti pozivom getURL() metoda: public URL getURL() HyperlinkEvent se ispaljuju ne samo kada korisnik klikne na link, već i kada miš uđe ili izađe iz oblasti linka. Tako, želimo da proverimo tip događaja pre nego što promenimo stranu public HyperlinkEvent.EventType getEventType() vraća jednu od 3 mnemoničke konstante HyperlinkEvent.EventType.EXITED, HyperlinkEvent.EventType.ENTERED, HyperlinkEvent.EventType.ACTIVATED ovo nisu brojevi već statičke instance EventType unutrašnje klase klase HyperlinkEvent. Korišćenje njih umesto celobrojnih konstanti omogućava pažljiviju proveru tipova u vreme komajliranja

19 primer 4: LinkFollower implementacija HyperlinkListener interfejsa koja proverava ispaljeni događaj i, ako je to activated, prelazi na stranu u linku. Referenca na JEditorPane je smeštena u private polju klase tako da može da se uradi callback

20 primer 5: SimpleWebBrowser
vrlo jednostavan web browser registruje instancu LinkFolower klase da rukuje HyperlinkEvent-ima nema Back dugme, Location bar, bookmark-e i uopšte nikakve ”đinđuve” ali dopušta da surfujemo Web-om prateći linkove preostali aspekti korisničkog interfejsa koje želimo u stvarnom browser-u su uglavnom samo vežba programiranja GUI-ja, pa su izostavljeni Ali, zaista je zadivljujuće kako jednostavnim Swing čini pisanje web browser-a Jedna stvar koju ovaj browser ne radi je da ne prati linkove imenovane sidrom unutar tela određene HTML strane. Postoji protected scrollToReference() metod u JEditorPane koji može naći zadato imenovano sidro u trenutno prikazanom HTML dokumentu i repozicionira pane na to mesto. Možemo koristiti taj metod da dodamo tu funkcionalnost, ako tako želimo: protected void scrollToReference(String reference)

21 Direktno čitanje HTML-a
JEditorPane klasa uglavnom pretpostavlja da ćete obezbediti ili URL ili String-formu URL-a i prepustiti joj da rukuje svim detaljima dobijanja podataka iz mreže. Međutim, ona sadrži jedan metod koji dopušta da mi čitamo HTML direktno iz input stream-a. public void read(InputStream in, Object document) throws IOException

22 Ovaj metod može biti koristan ako treba da čitamo HTML iz lanca filter stream-ova, npr. da ga odzipujemo pre čitanja Takođe, može se koristiti kada želimo da izvršimo neki specifični handshaking sa serverom, kao što je obezbeđivanje username-a i password-a, umesto da pustimo da se desi podrazumevana konekcija

23 EditorKit htmlKit = jep.getEditorKitForContentType(”text/html”);
Prvi argument je stream iz koga će HTML biti pročitan, a drugi instanca javax.swing.text.html.HTMLDocument. (možemo koristiti neki drugi tip, ali onda će JEditorPane će tretirati stream kao plain tekst umesto kao HTML). Iako se može koristiti podrazumevani HTMLDocument() konstruktor za kreiranje HTMLDocument, objektu koji on kreira nedostaje mnogo detalja. Bolje je pustiti da javax.swing.text.html.EditorKit kreira dokument za nas EditorKit se može dobiti prosleđivanjem MIME type koji želimo da editujemo (u ovom slučaju text/html) metodu getEditorKitForContentType() klase JEditorPane: EditorKit htmlKit = jep.getEditorKitForContentType(”text/html”);

24 Konačno, pre čitanja iz stream-a, moramo da koristimo metod setEditorKit() JEditorPane klase da instaliramo javax.swing.text.html.EditorKit. Npr. jep.setEditorKit(htmlKit); Naredni fragment koristi ove tehnike da učita web stranu sa Ovde stream dolazi iz URL-a ipak (mučenje bez potrebe u odnosu na alternativu). Ipak, ovaj pristup nam omogućuje da čitamo iz gzipped fajla ili fajla na lokalnom uređaju, podatke koje je pisala druga nit, byte niz ili bilo šta drugo što može da se poveže sa stream-om

25 Primer 5a JEditorPane jep = new JEditorPane(); jep.setEditable(false);
EditorKit htmlKit = jep.getEditorKitForContentType(”text/html”); HTMLDocument doc = (HTMLDocument) htmlKit.createDefaultDocument(); jep.setEditorKit(htmlKit); try{ URL u = new URL(” InputStream in = u.openStream(); jep.read(in, doc); } catch(IOException ex){ System.err.println(ex); } JScrollPane scrollPane = new JScrollPane(jep); JFrame f = new JFrame(”Macfaq”); f.setContentPane(scrollPane); f.setSize(512, 342); EventQueue.invokeLater(new FrameShower(f));

26 Ovo će biti korisno ako želimo da izvršimo neku vrstu filtriranja. Npr
Ovo će biti korisno ako želimo da izvršimo neku vrstu filtriranja. Npr. možda želimo da uklonimo IMG tagove iz fajla pre njegovog prikazivanja Metodi naredne sekcije nam mogu pomoći u tome

27 Parsiranje HTML-a Ponekad želimo da čitamo HTML tražeći informaciju bez da je stvarno prikažemo na ekranu. Npr. više od jednog autora koje Harold zna je pisalo ”book ticker” program kako bi pratili svakog sata napredak svojih knjiga na bestseller listi na Amazon.com Najteži deo ovog programa nije dobijanje HTML-a. To je čitanje HTML-a i traženje linije koja sadrži rang knjige. Drugi primer, razmotrimo Web Whacker-style program koji download-uje web sajt ili njegov deo na lokalni PC sa svim linkovima netaknutim. Download-ovanje fajlova kada imamo URL-ove je jednostavno. Ali čitanje dokumenta prilikom traganja za URL-ovima linkovanih strana je znatno kompleksnije. Oba ova problema su problemi parsiranja.

28 parsiranje jasno definisanog jezika koji ne dopušta sintaksne greške, poput Jave ili XML-a, je relativno pravolinijsko parsiranje fleksibilnog jezika koji pokušava da se oporavi od grešaka, kao što je HTML, je ekstremno teško lakše je pisati u HTML-u nego u striktnom jeziku kao što je XML, ali je mnogo teže čitati takav jezik. Lakoća korišćenja za autora strane ide po cenu lakoće razvoja za programera Srećom, javax.swing.text.html i javax.swing.text.html.parser paketi uključuju klase koje rade većinu teškog posla za nas. Primarno su namenjene za internu upotrebu klase JEditorPane. Zato je malo mučno doći do njih. Konstruktori često nisu public ili su skriveni u unutrašnjim klasama, i same klase nisu dobro dokumentovane. Ali, nakon što se vidi nekoliko primera, nije teško koristiti ih.

29 HTMLEditorKit.Parser Glavna HTML parser klasa je unutrašnja klasa javax.swing.html.HTMLEditorKit.Parser: public abstract static class HTMLEditorKit.Parser extends Object pošto je klasa apstraktna, stvarno parsiranje vrši instanca konkretne potklase javax.swing.text.html.parser.ParserDelegator: public class ParserDelegator extends HTMLEditorKit.Parser

30 Instanca ove klase čita HMTL dokument od Reader-a
Instanca ove klase čita HMTL dokument od Reader-a. Traži 5 stvari u dokumentu: start-tagove, end-tagove, empty-element tagove, tekst i komentare. To pokriva sve bitne delove uobičajenog HTML fajla. Svaki put kada parser vidi nešto od toga, poziva odgovarajući callback metod odgovarajuće instance klase javax.swing.text.html.HTMLEditorKit.ParserCallback Da bismo parsirali HTML fajl, pišemo potklasu HTMLEditorKit.ParserCallback koja odgovara na tekst i tagove po našoj volji. Zatim prosleđujemo instancu naše potklase metodu parse() klase HTMLEditorKit.Parser, zajedno sa Reader-om iz kog će HTML biti čitan:

31 public void parse(Reader in, HTMLEditorKit
public void parse(Reader in, HTMLEditorKit.ParserCallback callback, boolean ignoreCharacterSet) throws IOException Treći argument ukazuje da li želimo da budemo obavešteni o karakterskom skupu dokumenta, pod pretpostavkom da je nađen u META tagu u zaglavlju HTML-a. Ovo će obično biti true. Ako je false, parser izbacuje javax.swing.text.ChangedCharSetException kada je META tag u zaglavlju korišćen da promeni karakterski skup. Ovo nam daje priliku da promenimo Reader u onaj koji razume taj karakterski skup i reparsira dokument (ovog puta postavljajući ignoreCharSet na true pošto već znamo karakterski skup)

32 parse() je jedini public metod u klasi HTMLEditorKit.Parser
Sav posao se odrađuje unutar callback metoda u potklasi HTMLEditorKit.ParserCallback Metod parse() prosto čita iz Reader-a in dok ne pročita čitav dokument. Svaki put kada vidi tag, komentar ili blok teksta, poziva odgovarajući callback metod u HTMLEditorKit.ParserCallback instanci. Ako Reader izbaci IOException, izuzetak on se prosledi. Pošto ni HTMLEditorKit.Parser ni HTMLEditorKit.ParserCallback instance nisu specifične za jedan reader, mogu se koristiti za parsiranje većeg broja fajlova prosto pozivanjem parse() metoda nekoliko puta. Ako to uradimo, naša HTMLEditorKit.ParserCallback klasa mora biti potpuno thread-safe, pošto se parsiranje dešava u odvojenoj niti i parse() obično vraća kontrolu pre nego što se parsiranje završi

33 Pre nego što možemo da uradimo išta od ovoga, međutim, treba nam pomoć klase HTMLEditorKit.Parser i to je teže nego što bi trebalo biti. HTMLEditorKit.Parser je apstraktna klasa, pa se ne može instancirati direktno. Njena potklasa javax.swing.text.html.parser.ParserDelegator je konkretna. Međutim, pre nego što možemo da je koristimo, moramo da je konfigurišemo sa DTD, koristeći protected statičke metode ParserDelegator.setDefaultDTD() i ParserDelegator.createDTD(): protected static void setDefaultDTD() protected static DTD createDTD(DTD dtd, String name)

34 protected HTMLEditorKit.Parser getParser()
Dakle, da bismo kreirali ParserDelegator, prvo treba da imamo instancu klase javax.swing.text.html.parser.DTD. Ova klasa predstavlja Standardized General Markup Language (SGML) document type definition. Klasa DTD ima protected konstruktor i mnogo protected metoda koje potklase mogu da koriste da izgrade DTD od nule, ali ovo je API koji samo SGML eksperti treba da koriste. Uobičajeni način na koji se kreiraju DTD-ovi je čitanjem tekstualne forme standardnog DTD-a koji je objavio neko poput W3C. Trebalo bi da možete da dobijete DTD za HTML koristeći DTDParser klasu da parsirate W3C-jev objavljeni HTML DTD. Na žalost, DTDParser klasa nije uključena u objavljeni Swing API, pa ne možete. Tako da morate da prođete kroz zadnja vrata da kreirate instancu HTMLEditorKit.Parser instancu. Ono što ćemo raditi je da ćemo koristiti metod HTMLEditorKit.Parser.getParser(), koji na kraju vraća ParserDelegator nakon što ispravno inicijalizuje DTD za HTML 3.2: protected HTMLEditorKit.Parser getParser() Pošto je ovaj metod protected, prosto izvedemo potklasu iz HTMLEditorKit i predefinišemo ga public verzijom

35 Primer 6: ParserGetter demonstrira prethodno opisani postupak
sada kada imamo način da dobijemo parser, spremni smo da parsiramo dokumente to se radi metodom parse() klase HTMLEditorKit.Parser: public abstract void parse(Reader input, HTMLEditorKit.ParserCallback callback, boolean ignoreCharSet) throws IOException

36 Reader je pravolinijski
Reader je pravolinijski. Prosto olančamo InputStreamReader na stream koji čita HTML dokument, verovatno onaj koji je vratio openStream() metod klase java.net.URL. Kao treći argument prosleđujemo true da ignorišemo kodiranje (ovo generalno funkcioniše ako smo prilično sigurni da imamo posla sa ASCII tekstom) ili false ako želimo da primimo ChangedCharSetException kada dokument ima META tag koji ukazuje na karakterski skup. Drugi argument: gde je ono gde je akcija. Pisaćemo potklasu od HTMLEditorKit.ParserCallback koji biva obavešten o svakom start-tagu, end-tagu, empty-element tagu, tekstu, komentaru i grešci koju parser otkrije

37 HTMLEditorKit.ParserCallback
Klasa ParserCallback je public unutrašnja klasa u javax.swing.text.html.HTMLEditorKit: public static class HTMLEditorKit.ParserCallback extends Object ona ima jedan public podrazumevani konstruktor: public HTMLEditorKit.ParserCallback()

38 Međutim, verovatno ga nećemo koristiti direktno pošto standardna implementacija klase ne radi ništa. Ona postoji da bi iz nje bile izvođene potklase. Ima 6 callback metoda koji ne rade ništa Predefinisaćemo ove metode da odgovore na specifične stavke na koje se nailazi u ulaznom stream-u prilikom parsiranja dokumenta:

39 public void handleText(char[] text, int position)
public void handleComment(char[] text, int position) public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, int position) public void handleEndTag(HTML.Tag tag, int position) public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes, int position) public void handleError(String errorMessage, int position)

40 public void flush() throws BadLocationException
Primer 7: TagStripper Postoji takođe i flush() metod koji koristimo za konačno čišćenje. Parser poziva ovaj metod jednom nakon što je završio parsiranje dokumenta: public void flush() throws BadLocationException PRIMER 7: Jednostavan primer. Pretpostavimo da želimo da napišemo program koji odstranjuje sve tagove i komentare iz HTML dokumenta i ostavlja samo tekst. Napisaćemo potklasu od HTMLEditorKit.ParserCallback koja predefiniše handleText() metod da piše tekst u Writer. Ostale metode ćemo ostaviti netaknute.

41 Pretpostavimo sada da želimo da koristimo ovu klasu da zaista odstranimo tagove iz URL-a.
Počinjemo tako što dobijemo parser koristeći ParserGetter klasu: ParserGetter kit = new ParserGetter(); HTMLEditorKit.Parser parser = kit.getParser(); Zatim konstruišemo instancu naše callback klase na sledeći način: HTMLEditorKit.ParserCallback callback = new TagStripper(new OutputStreamWriter(System.out));

42 Onda dohvatamo stream kojim možemo da čitamo iz HTML dokumenta. Npr.
try{ URL u = new URL(” InputStream in = new BufferedInputStream(u.openStream()); InputStreamReader r = new InputStreamReader(in); // konacno prosledjujemo Reader i // HTMLEditorKit.ParserCallback metodu parse() klase // HTMLEditorKit.Parser parser.parse(r, callback, false); }catch(IOException ex){ System.err.println(ex); }

43 Ima par detalja o procesu parsiranja koji nisu očigledni
Prvo, parser parsira u odvojenoj niti Zato ne treba pretpostavljati da je parsiranje završeno kada metod parse() vrati kontrolu. Ako koristimo isti HTMLEditorKit.ParserCallback objekat za dva odvojena parsiranja, treba da učinimo sve naše callback metode thread-safe. Drugo, parser zapravo preskače neke podatke na ulazu. Posebno, on normalizuje i odstranjuje beline. Ako ulazni dokument sadrži sedam blankova u nizu, parser ih konvertuje u jedan blanko. Carriage returns, line feeds, i tabovi se svi konvertuju u jedan blanko, tako da gubimo oznake krajeva redova. Dalje, od većine tekstualnih elemenata se odstranjuju vodeće i krajnje beline. Elementi koji sadrže samo beline kompletno se eliminišu. Tako, pretpostavimo da ulazni dokument sadrži: <H1> Here’s the Title </H1> <P> Here’s the text </P> Ono što izađe iz tag stripper-a je: Here’s the TitleHere’s the text

44 Jedini izuzetak je PRE element, koji zadržava sve beline u svom sadržaju needitovanim.
Ako pišemo svoj parser, ne postoji način da očuvamo sve odstranjene beline. Ali možemo uključiti minimum neophodnih krajeva linija i belina gledajući i tagove i tekst. Generalno, očekujemo prelazak u novi red (single break) u HTML kada vidimo jedan od tagova: <BR> <LI> <TR> A očekujemo double break (paragraph break) kada vidimo jedan od ovih tagova: <P> </H1> </H2> </H3> </H4> </H5> </H6> <HR> <DIV> </UL> </OL> </DL> Da uključimo prelome linija u izlaz, moramo da pogledamo svaki tag nakon što je procesiran i da odredimo da li upada u jedan od ovih skupova. Ovo je pravolinijsko jer je prvi argument koji se prosleđuje svakom od tag callback metoda HTML.Tag objekat.

45 public static class HTML.Tag extends Object
Tag je public unutrašnja klasa u javax.swing.text.html.HTML klasi public static class HTML.Tag extends Object ima sledeća 4 metoda: public boolean isBlock() public boolean breaksFlow() public boolean isPreformatted() public String toString();

46 breaksFlow() metod vraća true ako tag treba da uzrokuje single line break
isBlock() metod vraća true ako tag treba da uzrokuje double line break isPreformatted() metod vraća true ako tag ukazuje da beline treba da se očuvaju. Ovo čini jednostavnim da se na izlazu obezbede odgovarajući break-ovi

47 Verovatno je da ćemo videti više tagova nego što očekujemo kada parsiramo fajl
Parser umeće nedostajuće zatvarajuće tagove. Drugim rečima, ako dokument sadrži samo <P> tag, parser će prijaviti i <P> start-tag i implicitni </P> end-tag na odgovarajućim mestima u dokumentu

48 Primer 8: LineBreakingTagStripper
program koji radi najbolje što može da konvertuje HTML u čist tekst Traži empty i end-tagove, eksplicitne ili implicitne i, ako tag ukazuje da su potrebni prelomi linija, ubacuje potreban broj njih Veći deo vremena, naravno, želimo da znamo značajno više nego da li tag prelama liniju. Želimo da znamo koji je to tag i da se ponašamo na odgovarajući način

49 Testiramo tip taga tako što ga poredimo sa 73 mnemoničke konstante iz klase HTML.Tag:
HTML.Tag.A, HTML.Tag.FRAMESET, HTML.Tag.PARAM, HTML.Tag.ADDRESS, HTML.TAG.H1 ... ovo nisu konstante tipa int. One su objektne konstante koje dopuštaju proveru tipa u vreme kompajliranja. Taj trik smo već videli u klasi javax.swing.event.HyperlinkEvent. Svi HTML.Tag elementi prosleđeni našim callback metodima biće neke od ove 73 konstante. Ne da će biti iste kao ova 73 objekta, već su to ta 73 objekta. Postoji tačno 73 objekta u ovoj klasi, ni manje, ni više. Poređenje se može vršiti sa == ili sa equals().

50 Primer 9: Outliner Pretpostavimo da nam treba program koji skicira HTML strane ekstrahujući njihova H1 do H6 zaglavlja a ostatak dokumenta ignoriše Organizuje skicu kao ugnježdene liste u kojima je svako H1 zaglavlje top level, svako H2 zaglavlje jedan nivo dublje itd. Napisaćemo HTMLEditorKit.ParserCallback potklasu koja izdvaja sadržaj svih H1,...,H6 elemenata, a ignoriše sve ostale

51 Kada se pronađe start-tag zaglavlja, metod handleStartTag() emituje neophodan broj <ul>, </ul> i <li> tagova. Dalje, fleg inHeading se postavlja na true, tako da metod handleText() zna da treba da ispiše sadržaj zaglavlja svi start-tagovi osim 6 nivoa zaglavlja se prosto ignorišu metod handleEndTag() razmatra tagove zaglavlja samo poredeći tagove koje prima i 7 tagova za koje je zainteresovan. Ako vidi tag zaglavlja, postavlja fleg inHeading na false ponovo, tako da se tekst neće emitovati metodom handleText(). Ako vidi kraj dokumenta </html>, uradi flush(). Inače, ne radi ništa. Krajnji rezultat je lepo formatirana grupa ugnježdenih, neuređenih lista koje skiciraju dokument. Outliner1.java: vrši se i indent-acija za odgovarajući broj tabulatora

52 Atributi Kada procesiramo HTML fajl, često treba da pogledamo i atribute drugi argument handleStartTag() i handleSimpleTag() callback metoda je instanca klase javax.swing.text.MutableAttributeSet Ovaj objekat nam omogućava da vidimo koji atributi su pridruženi tagu MutableAttributeSet je podinterfejs interfejsa javax.swing.text.AttributeSet

53 I AttributeSet i MutableAttributeSet predstavljaju kolekciju atributa HTML taga. Razlika je u tome što MutableAttributeSet interfejs deklariše metode za dodavanje ili uklanjanje atributa i prolazak kroz atribute skupa. Sami atributi su predstavljeni kao parovi java.lang.Object objekata, jedan za ime atributa i jedan za vrednost.

54 AttributeSet interfejs deklariše metode:
public int getAttributeCount() public boolean isDefined(Object name) public boolean containsAttribute(Object name, Object value) public boolean containsAttributes(AttributeSet attributes) public boolean isEqual(AttributeSet attributes) public AttributeSet copyAttributes() public Enumeration getAttributeNames() public Object getAttribute(Object name) public AttributeSet getResolveParent()

55 getAttributeCount() metod vraća broj atributa u skupu
isDefined() metod vraća true ako je atribut sa zadatim imenom u skupu, false inače containsAttribute(Object name, Object value) metod vraća true ako je atribut sa datim imenom i vrednošću u skupu containsAttributes(AttributeSet attributes) metod vraća true ako su svi atributi u zadatom skupu u ovom skupu sa istim tim vrednostima, tj. ako je argument podskup skupa za koji je ovaj metod pozvan isEqual() metod vraća true ako je pozivajući AttributeSet isti kao argument copyAttribute() metod vraća klone tekućeg AttributeSet-a getAttributeNames() vraća java.util.Enumeration imena svih atributa u skupu Kada znamo ime jednog od elemenata u skupu, getAttribute() metod vraća njegovu vrednost. getResolveParent() metod vraća roditeljski AttributeSet, koji će biti pretražen za atribute koji nisu nađeni u tekućem skupu.

56 za dati AttributeSet, ovaj metod štampa atribute u formatu name=value:
private void listAttributes(AttributeSet attributes){ Enumeration e = attributes.getAttributeNames(); while(e.hasMoreElements()){ Object name = e.nextElement(); Object value = attributes.getAttribute(name); System.out.println(name + ”=” + value); }

57 Iako su argument i povratni tipovi ovih metoda uglavnom deklarisani u terminima java.lang.Object, u praksi, sve vrednosti su instance java.lang.String, dok su sva imena instance public unutrašnje klase javax.swing.text.html.HTML.Attribute. Kao što HTML.Tag predefiniše 73 HTML taga i koristi private konstruktor kako bi sprečio da drugi kreiraju, tako i HTML.Attribute klasa predefiniše 80 standardnih HTML atributa (HTML.Attribute.ACTION, HTML.Attribute.ALIGN, HTML.Attribute.ALINK, HTML.Attribute.ALT, itd.) i sprečava konstrukciju drugih.

58 MutableAttributeSet interfejs dodaje 6 metoda da doda i ukloni atribute iz skupa:
public void addAttribute(Object name, Object value) public void addAttributes(AttributeSet attributes) public void removeAttribute(Object name) public void removeAttributes(Enumeration name) public void removeAttributes(AttributeSet attributes) public void setResolveParent(AttributeSet parent) Ponovo, vrednosti su stringovi a imena HTML.Attribute objekti

59 Jedna moguća upotreba svih ovih metoda je modifikovanje dokumenata pre njihovog čuvanja i prikazivanja. Npr. većina web browsera nam omogućava da sačuvamo stranu na svom hard disku kao HTML ili kao tekst. Međutim, oba ova formata gube vezu sa slikama i relativnim linkovima Problem je što je većina strana puna relativnih URL-ova a oni se svi raskidaju kada pomerimo stranu na svoju lokalnu mašinu

60 Primer 10: PageSaver aplikacija koja download-uje web stranu na lokalni hard uređaj ali čuva sve linkove tako što prepisuje sve relativne URL-ove kao apsolutne URL-ove. Klasa PageSaver čita niz URL-ova iz komandne linije. Otvara svaki i parsira ga. Svaki tag, blok teksta, komentar i atribut se kopira u lokalni fajl. Međutim, svi link atributi, poput SRC, LOWSRC, CODEBASE i HREF se remapiraju u apsolutni URL. Posebno, primetimo intenzivnu upotrebu URL i javax.swing.text PageSaver se može prepisati string zamenama, ali to bi bilo značajno komplikovanije

61 handleEndTag(), handleText() i handleComment() metodi prosto kopiraju svoj sadržaj sa ulaza na izlaz
handleStartTag() i handleSimpleTag() metodi pišu svoje tagove na izlaz, ali takođe pozivaju i private writeAttributes() metod. Ovaj metod prolazi kroz atribute skupa i uglavnom ih kopira na izlaz. Međutim, za nekoliko odabranih atributa, kao što su SRC i HREF, koji tipično imaju URL vrednosti, on prepisuje vrednosti kao apsolutne URL-ove. Konačno, main() metod čita URL-ove iz komandne linije, računa imena i direktorijume za odgovarajuće lokalne fajlove i pokreće novi PageSaver za svaki URL

62 Ovo je samo jedan od raznih primera HTML filtera koje javax. swing
Ovo je samo jedan od raznih primera HTML filtera koje javax.swing.text.html paket čini jednostavnim za pisanje. Mogli bismo, npr. da napišemo filter koji lepo ispisuje HTML uvlačenjem različitih nivoa tagova. Možemo napisati program koji konvertuje HTML u TeX, XML, RTF ili mnoge druge formate Možemo napisati program koji sa sajta skida sve linkovane stranice Svi ovi programi su jednostavni za pisanje jer Swing obezbeđuje HTML parser koji je jednostavan za upotrebu. Sve što mi treba da uradimo jeste da odgovorimo na pojedinačne elemente i atribute koje parser pronalazi u HTML dokumentu. page 40 of 52: Cookies


Download ppt "Mrežno računarstvo glava 8 HTML in Swing."

Similar presentations


Ads by Google