Nội dung của luận văn sẽ nghiên cứu cơ chế hoạt động của Mozilla, đặt biệt là cơ chế phân tích giải mã, để sau đó phân tích và thiết kế một engine tích hợp vào trong Mozilla có tính năng
Trang 1TRƯƠNG NGỌC TUẤN
ĐỀ TÀI LUẬN VĂN THẠC SĨ :
Xây dựng một browser có thể hiển thị đúng nội dung tiếng Việt
của các trang web tiếng Việt sử dụng bảng mã bất kỳ
Chuyên ngành : Công nghệ thông tin
Mã ngành : 01.02.10
LUÂÄN VĂN THẠC SĨ
TP HỒ CHÍ MINH, THÁNG 9 NĂM 2003
Trang 2Người hướng dẫn :
Tiến sĩ Nguyễn Văn Hiệp
Khoa Công nghệ thông tin
Trường Đại học Bách Khoa TPHCM
Người phản biện :
Tiến sĩ Cao Hoàng Trụ
Khoa Công nghệ thông tin
Đại học Bách khoa TPHCM
Tiến sĩ Đỗ Phúc
Trung tâm Phát triển Công nghệ thông tin Đại học Quốc gia TPHCM
Trang 3NHIỆM VỤ LUẬN VĂN THẠC SĨ
Họ và tên học viên : Trương Ngọc Tuấn Phái : Nam
Ngày tháng năm sinh : 07 tháng 08 năm 1960 Nơi sinh : Sài Gòn Chuyên ngành : Công Nghệ Thông Tin Mã số : 01 02 10
I- TÊN ĐỀ TÀI : Xây dựng một browser có thể hiển thị đúng nội dung tiếng Việt
của các trang web tiếng Việt sử dụng bảng mã bất kỳ
II– NHIỆM VỤ VÀ NỘI DUNG :
- Nghiên cứu và phân tích mã nguồn mở Mozilla
- Thiết kế giải thuật phát hiện và chuyển đổi mã chữ Việt sang Unicode
- Tích hợp chức năng phát hiện và chuyển đổi mã vào Mozilla
- Hiện thực trên môi trường Mozilla
III- NGÀY GIAO NHIỆM VỤ :
IV- NGÀY HÒAN THÀNH NHIỆM VỤ : 30/09/2003
V- HỌ VÀ TÊN CÁN BỘ HƯỚNG DẪN : Tiến Sĩ Nguyễn Văn Hiệp
CÁN BỘ HƯỚNG DẪN CHỦ NHIỆM NGÀNH BỘ MÔN QUẢN LÝ NGÀNH
Nội dung đề cương luận văn thạc sĩ đã được Hội Đồng Chuyên Ngành thông qua
Ngày tháng năm
PHÒNG ĐÀO TẠO SĐH KHOA QUẢN LÝ NGÀNH
Trang 4
♥ Tôi chân thành bày tỏ lòng tri ân với Tiến sĩ Nguyễn Văn Hiệp, người Thầy đã tận tình hướng dẫn và giúp đỡ tôi trong suốt thời gian thực hiện luận án này
♥ Tôi cũng chân thành cám ơn Thầy Tiến sĩ Cao Hoàng Trụ và Thầy Tiến Sĩ Đỗ Phúc đã bỏ nhiều thời gian bổ sung cho tôi những ý kiến quý báu để hoàn thiện luận án
♥ Tôi cũng xin bày tỏ lòng biết ơn với Tiến sĩ Dương Tuấn Anh, người Thầy đã theo dõi, hướng dẫn và giúp đỡ, đồng thời tạo điều kiện thuân lợi về thời gian để tôi có thể hoàn thành luận án này
♥ Cuối cùng tôi cũng xin bày tỏ lời cám ơn chân thành đến tất cả các Thầy, Cô đã truyền đạt cho tôi kiến thức trong suốt các học phần Cao học từ 1999-2002
Trang 5Ngày nay, cùng với sự phát triển của công nghệ thông tin, nhu cầu sử dụng máy tính trong đời sống hàng ngày càng phổ biến Các website trên Internet dần dần trở thành một phương tiện hiệu quả cho việc trao đổi thông tin Nhiều tổ chức, doanh nghiệp, và cá nhân đã tạo những website riêng cho mình Tuy nhiên, ở một khía cạnh khác, điều này lại dẫn đến một tình trạng khá phiền toái là, do các website tiếng Việt không sử dụng thống nhất một bảng mã chữ Việt nên đã gây khó khăn cho người xem Để có thể hiển thị đúng ký tự chữ Việt, trên máy người xem cần phải có cài đúng bảng mã chữ Việt và font chữ dùng trong trang web Điều này thực sự khó khăn cho người xem vì thông thường họ không biết được bảng mã dùng trong trang web là bảng mã nào Đây là một sự bế tắc cho người xem
Vì thế, mục đích của luận án này là xây dựng một browser có thể giúp cho người xem tránh được tình trạng này, tức là có thể tự động hiển thị đúng các trang web tiếng Việt cho dù bảng mã sử dụng là bảng mã nào, nhưng không cần đòi hỏi trên máy người xem phải có cài bảng mã đó Hơn nữa, browser này lại có tính độc lập môi trường nên có thể ứng dụng trên nhiều hệ điều hành
Browser này sẽ được xây dựng dựa trên Mozilla, một browser có mã nguồn mở là một phiên bản của Netscape Navigator Nội dung của luận văn sẽ nghiên cứu cơ chế hoạt động của Mozilla, đặt biệt là cơ chế phân tích giải mã, để sau đó phân tích và thiết kế một engine tích hợp vào trong Mozilla có tính năng tự động phát hiện mã chữ Việt và chuyển đổi sang mã Unicode để có thể hiển thị đúng trên Mozilla Font chữ Việt cũng sẽ được chuyển cho thích hợp với mã Unicode
Với browser này người xem có thể thoải mái duyệt các website tiếng Việt mà không phải lo lắng về bảng mã chữ Việt mà trang web sử dụng như trước đây nữa
Trang 6Nowadays, as the information technology grows more and more, the need of using computer comes more and more popular in Vietnam Web sites in the Internet gradually become a potential means for information exchanges Many organizations, businesses, and individuals have their own websites But on the other side, it emerges a really annoyed problem: as the character sets used in Vietnamese web pages are not unique, so it is difficult for the viewers to make them correctly showned on their browser It requires the viewers to have the appropriate character set, or more precisely, the appropriate fonts, installed on their computers to view the web page correctly It is really difficult for the viewers to do that, because in general, they don’t, or they can’t, know what character set and what fonts being used in the web page And in the worse cases, the viewers don’t know where to find the appropriate character set code and how to install it on their computer They will really be stuck in this problem
So, the intention of this thesis is to build a browser that can help the viewer to avoid the problem above, that is, a browser that can automatically and correctly show any Vietnamese web page regardless of the Vietnamese character set used in that page, and does not have any additional requirement for the viewer Moreover,
to be widely applied, this browser will be designed to be portable
The browser will be built based on Mozilla, the open-source version of Netscape Navigator This thesis will inspect the mechanism of Mozilla, particularly the mechanism of parsing, then analyzes and gives a design for a Vietnamese-supported engine that will automatically detect the Vietnamese character set and will convert Vietnamese characters, as well as the font they use, into Unicode characters under an appropriate font
With this browser, the user can navigate from one Vietnamese web page to another Vietnamese web page with no worry about the character set and the fonts they use The only thing they need is the browser, and no additional character set required to be installed The users will get totally comfortable with this browser when they navigate around the Internet
Trang 7Chương 1 Mục tiêu và nội dung của đề tài 1
Chương 2 Những vấn đề nghiên cứu có liên quan 2.1 Các bảng mã chữ Việt và mã Unicode 4
2.2 Mô tả sơ lược về ngôn ngữ HTML và XML 8
Chương 3 Phân tích và tìm hiểu mã nguồn Mozilla 3.1 Tìm hiểu về cơ chế hoạt động của Mozilla 14
3.2 Mô tả tổng quát quá trình hiển thị 24
một trang web trong Mozilla 3.3 Mô tả tổng quát việc phân tích giải mã 29
trong Mozilla 3.4 Khảo sát chi tiết hơn về cơ chế phân tích 33
cú pháp trong Mozilla 3.5 Các dạng chuỗi dùng trong Mozilla 37
3.6 Đối tượng iterator và các hàm xử lý chuỗi 39
thường dùng Chương 4 Thiết kế và giải thuật 41
4.1 Phát hiện và chuyển đổi mã tiếng Việt 43
4.2 Chuyển đổi font tiếng Việt cho thích hợp 69
Chương 5 Hiện thực chương trình 75
Chương 6 Kết luận 86
Trang 8Ngày nay, ở Việt Nam nhu cầu sử dụng Internet ngày càng tăng Ngày càng nhiều trang web với nội dung tiếng Việt được đưa lên mạng Các trang web tiếng Việt này được soạn thảo bởi nhiều cá nhân, cơ quan, tổ chức khác nhau Và
vì vậy, việc sử dụng các bộ mã tiếng Việt để biên soạn các trang web cũng rất tùy tiện, chưa có quy định thống nhất Đa số các trang web thường sử dụng bộ mã chữ Việt VNI hoặc TCVN3 Gần đây, nhiều trang web tiếng Việt chuyển sang dùng mã Unicode Lại có một số trường hợp nhiều bộ mã chữ Việt được dùng chung lẫn lộn trong cùng một trang web
Điều này dẫn đến tình trạng khá phiền toái cho người truy cập vì để hiển thị đúng được nội dung tiếng Việt của một trang web, trên máy của người xem phải được cài sẵn đúng bộ mã chữ Việt và phải có đúng font chữ Việt dùng cho trang web đó, và đôi khi người xem cũng phải biết chọn đúng giá trị thích hợp cho các setting của browser (option Font trong menu Tools nếu người xem dùng browser là Internet Explorer )
Do đó, khi người xem chuyển từ một trang web này sang một trang web khác thì vấn đề lại đặt ra cho người xem là trên máy đã có sẵn bộ mã và các font chữ dùng trong trang web hay không
Khó khăn hơn nữa cho người xem là phải biết được trang web mình đang xem sử dụng bộ mã chữ Việt nào và font nào Điều này là một khó khăn lớn cho người xem vì đôi khi các trang web tiếng Việt không cho biết bộ mã đang sử dụng là bộ mã nào
Như vậy, để có thể xem được các trang web tiếng Việt, người xem thường gặp phải hai trở ngại là trước hết phải biết bộ mã sử dụng cho trang web đang xem là bộ mã nào, sau đó phải đảm bảo rằng bộ mã chữ Việt đó đã được cài trên máy và các setting trên browser là phù hợp
Để cải thiện điều này, hiện nay có một số biện pháp
Trang 9ngay trong trang web Nhờ vậy, khi trang web được tải về máy người xem thì các font cần thiết cho trang web cũng được tải về Và do đó, cho dù trước đó trên máy người xem không có những font yêu cầu nhưng trang web vẫn được hiển thị đúng chữ Việt
Tuy nhiên biện pháp này chỉ có tác dụng giới hạn cho một số trang web tiếng Việt có tích hợp font chữ Việt, còn đối với những trang web tiếng Việt khác thì cuối cùng người xem cũng phải tự giải quyết lấy vấn đề hiển thị đúng chữ Việt cho trang web
• Một biện pháp khác để tránh khó khăn cho người xem trong việc cho hiển thị đúng chữ Việt, các trang web tiếng Việt hiện nay có khuynh hướng chuyển sang dùng bộ mã Unicode Biện pháp này có nhiều triển vọng trong tương lai vì bộ mã Unicode được tích hợp vào các hệ điều hành Windows từ 98 trở lên, và trong Unicode, các chữ cái tiếng Việt đã được định nghĩa sẵn nằm trong bộ chữ cái la tinh
Nhờ vậy nên browser trên các hệ điều hành Windows 98 trở lên có thể hiển thị đúng chữ tiếng Việt dùng mã Unicode mà không cần phải cài đật gì thêm Một trở ngại nhỏ cho biện pháp này là hiện nay vẫn chưa có sự thống nhất trong việc chọn cách biểu diễn các ký tự chữ Việt bằng mã Unicode bởi vì hiện nay có hai dạng thường dùng để biểu diễn các ký tự Unicode là UCS-2 và UTF-8
Thế nhưng cho dù có dùng mã Unicode cho các trang web tiếng Việt thì đó cũng chỉ là cách giải quyết cho các trang web hiện nay và sau này, còn đối với những trang web tiếng Việt đã được xây dựng trước đó (không dùng mã Unicode) thì người xem vẫn gặp phiền toái trong việc cho chúng hiển thị đúng tiếng Việt
• Giải pháp thứ ba là người xem có thể dùng các phần mềm hổ trợ tiếng Việt như Web-eye Các phần mềm này sẽ được cho khởi động trước khi khởi động browser, và có thể giúp người xem đọc được chữ Việt trên các trang web
Một hạn chế của phần mềm này là chỉ sử dụng được trên một số hệ điều hành nhất định, đồng thời làm giảm bớt tài nguyên của máy khá đáng kể vì nó phải thường xuyên xử lý các ký tự kết xuất ra màn hình
Trang 10một giải pháp tốt hơn, nên nội dung của luận án này là xây dựng một browser có tính “trong suốt” với mọi bộ font tiếng Việt, nhằm giúp cho người truy cập Internet có thể thoải mái khi xem các trang web tiếng Việt, không còn phải lo âu về bộ mã chữ Việt dùng trong trang web là bộ mã nào, cũng như font chữ dùng trong trang web là những font gì
Hơn nữa, người xem cũng không cần phải thực hiện những thao tác khai báo phức tạp nào Ngoài ra, browser này cũng sẽ được xây dựng trên tinh thần không phụ thuộc vào hệ điều hành của máy đang sử dụng Do đó có thể dùng cho cả các máy chạy Windows lẫn Unix, Linux và MacinTosh
Để thực hiện được mục đích này, hướng tiến hành của luận án là sẽ dựa vào bộ mã nguồn mở Mozilla Mozilla là một browser, nền tảng của Netscape Navigator, với tính năng độc đáo là không phụ thuộc hệ điều hành, và mã nguồn Mozilla là mã nguồn mở, luôn được bổ sung, cập nhật và được quản lý bởi một tổ chức có tên Mozilla
Do vậy, tận dụng bộ mã nguồn Mozilla sẽ rút ngắn được một quãng đường dài cho luận án Vì vậy, nhiệm vụ chính còn lại là bổ sung thêm chức năng xử lý mã chữ Việt vào trong browser Mozilla
Trang 11
2.1 Các bảng mã chữ Việt và mã Unicode
Hiện nay vẫn chưa có một hướng thống nhất trong việc mã hóa chữ Việt vì có khá nhiều phương thức để mã hóa Mặc dù tháng 7/2002 bộ mã TCVN đã được Nhà nước công bố là bộ mã chính thức của Việt Nam, nhưng nhiều cơ quan, tổ chức đã đưa ra những cách thức mã hóa riêng, do đó nhiều bộ mã chữ Việt vẫn cùng tồn tại và có những ưu khuyết điểm riêng
Các bộ mã chữ Việt thông dụng nhất hiện nay gồm có mã TCVN3 ( còn gọi là bộ mã ABC, là bộ mã được nhiều cơ quan nhà nước dùng trong các văn bản chính thức ), mã VNI ( rất thông dụng và quen thuộc với mọi người ), mã Bách Khoa TPHCM ( được nhiều người thích vì có các font chữ đẹp ) và bộ mã VietWare Cũng cần nói thêm, mỗi một bộ mã chữ Việt sẽ gồm có nhiều font chữ khác nhau dùng cho bộ mã đó Các font chữ của những bộ mã khác nhau thì luôn luôn có tên khác nhau, thí dụ các font chữ của bộ mã VNI luôn có tên bắt đầu bằng VNI, các font chữ của TCVN3 thì luôn có tên bắt đầu bằng Vn, Nhờ có nguyên tắc này nên dựa vào tên của font chữ có thể biết được font chữ đó thuộc bộ mã nào
Ngoài các bộ mã nói trên, do người Việt soạn và áp dụng, còn có bộ mã Unicode, là một bộ mã đa ngôn ngữ do một tổ chức quốc tế mang tên Unicode Consortium soạn dùng cho các nước trên thế giới
Ngoại trừ mã Unicode, các bộ mã chữ Việt hiện nay có thể được phân làm hai loại, dựa vào số byte được dùng để mã hóa một mẫu tự chữ Việt là một hay hai byte
a) Bảng mã 1 byte : các bộ mã thuộc loại này dùng 1 byte để biểu diễn một chữ cái có dấu trong tiếng Việt Trong tiếng Việt, số ký tự có dấu cần mã hóa là
134 ký tự ( gồm 67 ký tự chữ thường và 67 ký tự chữ in hoa ) Do đó, trong phạm
vi giới hạn 256 ký tự của bộ mã ASCII mở rộng, thì việc dành ra thêm 134 ký tự ( ngoài những ký tự không dấu sẵn có và các ký tự đặc biệt đã được quy định trước
Trang 12Vì vậy, trong các bộ mã thuộc loại này (ngoại trừ bộ mã Bách khoa HCM1) thường thì mẫu tự in hoa và mẫu tự thường có chung một mã, và khi đó phải dùng hai font khác nhau để biểu diễn các mẫu tự thường và mẫu tự in hoa Đó là trường hợp của các bộ mã TCVN3, VietwareF Đây là một khó khăn cho việc chuyển mã từ một bộ mã 1 byte sang một bộ mã 2 byte
b) Bảng mã 2 byte : các bộ mã thuộc loại này không nhất thiết dùng đúng 1 byte để biểu diễn một ký tự chữ Việt, mà tùy thuộc vào từng ký tự chữ Việt, số byte dùng để mã hóa có thể là một hoặc hai Các bộ mã thông dụng thuộc loại này có thể kể là BKHCM2, VNI, VietwareX Vì có thể sử dụng hai byte để mã hóa, nên các bộ mã thuộc loại này không bị khuyết điểm như loại 1 byte nói trên, tức là, mỗi một mẫu tự đều có hai mã khác nhau ứng với dạng chữ thường và dạng chữ hoa
c) Bảng mã Unicode ( viết tắt từ Unification Code ): Vào đầu những năm
80, trên thến giới có hai tổ chức đồng thời thực hiện hai dự án khác nhau nhưng cùng chung một mục đích là xây dựng một bộ mã đa ngôn ngữ dùng chung cho cả thế giới Một trong hai tổ chức đó là ISO ( International Standardization Organization ) của Châu Âu, và tổ chức thứ hai là Unicode Consortium của Mỹ
Bộ mã của ISO xây dựng có tên là Universal Character Set (UCS), còn bộ mã của Mỹ xây dựng có tên là Unicode Ban đầu, Unicode là đề án của chỉ hai công ty Xerox và IBM Đến năm 1991, nhiều công ty hàng đầu của Mỹ như Microsoft, IBM, Xerox, Apple, Oracle, Sun và Netscape, tham gia đề án và thành lập tổ chức Unicode Consortium để quản lý đề án
Cũng trong năm đó, Unicode Consortium và ISO đồng ý hợp nhất với nhau để cùng xây dựng một bộ mã chung cho cả thế giới Mặc dù vậy, hai bộ mã UCS và Unicode vẫn cùng tồn tại nhưng chúng hoàn toàn tương thích với nhau (mã của các ký tự và tên của chúng trong hai bộ mã đều giống nhau)
Tài liệu do Unicode Consortium phát hành về bộ mã Unicode có tên là Unicode Standard, trong khi đó ISO phát hành bộ ISO 10646 quy định những chuẩn về bộ mã UCS Trước đó, ISO cũng đã ban hành bộ chuẩn ISO 8859 mà
Trang 13do đó khả năng biểu diễn của mã Unicode rất lớn Hiện nay, Unicode có thể biểu diễn cả các ký tự trong tiếng Ả rập, Thái Lan, Nhật Bản, Hàn Quốc, Trung Hoa và có cả các ký hiệu toán học và các ký hiệu thường dùng khác
Bộ chuẩn ISO 10646-1 được đưa ra năm 1993 (tương thích với chuẩn Unicode 1.1) quy định các ký tự thuộc phạm vi 16 bit đầu hay còn gọi là Basic Multilangual Plane (BMP – hay Plane 0) Các ký tự trong bộ mã ASCII được xếp trong khoảng 0x0000 đến 0x007F như đã mô tả trong chuẩn ISO 646 IRV Phạm
vi rộng hơn, từ 0x0000 đến 0x00FF được mô tả trong ISO 8859-1 (nhóm La tinh 1) Chuẩn ISO 10646-2 được đưa ra năm 2001 (tương ứng với chuẩn Unicode 4.0), quy định thêm một số ký tự nằm ngoài BMP, tất cả bao gồm 96382 ký tự [12] Các ký tự mới vẫn tiếp tục được thêm vào nhưng không làm thay đổi các ký tự đã có
Trong bộ mã Unicode hiện nay có quy định những ký tự dấu, là những ký tự phải kết hợp với một ký tự nào đó để tạo thành một ký tự có dấu ( bản thân ký tự dấu không chiếm một vị trí khi in ) Đồng thời, Unicode cũng có quy định sẵn các ký tự có dấu Việc quy định các ký tự dấu nhằm tạo sự linh động cho việc sử dụng các ký tự có dấu Nhưng vì trong các chuẩn trước đây ( như ISO 8859-1 ) không có quy định các ký tự dấu, nên những chuẩn Unicode sau này vẫn phải quy định các ký tự có dấu để tương thích với các chuẩn trước đây Do đó, có nhiều cách để biểu diễn một ký tự có dấu trong Unicode
Một vấn đề khác là vấn đề biểu diễn ký tự Unicode Từ trước đến nay, nhiều cách đã được đưa ra để biểu diễn một ký tự Unicode như UCS-2, UCS-4, UTF-8, UTF-16, UTF-32 Theo cách biểu diễn UCS-2, một ký tự được biểu diễn bởi 2 byte Do đó, để biểu diễn các ký tự ASCII chỉ cần thêm một byte 0x00 phía trước mỗi ký tự Tương tự, theo cách biểu diễn UCS-4, mỗi ký tự được biểu diễn bởi 4 ký tự, vì vậy để biểu diễn các ký tự ASCII chỉ cần thêm ba byte 0x00 phía trước mỗi ký tự
Tuy nhiên, hai cách biểu diễn UCS-2 và UCS-4 gây ra nhiều trở ngại khi dùng trong môi trường Unix, Linux Vấn đề gặp phải là các ký tự biểu diễn theo cách này thường bao gồm các chuỗi ký tự \0 hay / như là một phần trong chuỗi biểu diễn của ký tự, do đó thường gây ra nhầm lẫn vì \0 và / mang ý nghĩa đặc
Trang 14Transformation Format) được đưa ra để thay thế cách biểu diễn UCS-2 và UCS-4 trong các hệ Unix, Linux Hơn nữa, cách biểu diễn UTF-8 là một song ánh 1-1 nên khi chuyển đổi ngược lại từ UTF-8 sang mã Unicode không làm sai lệch dữ liệu
Theo cách biểu diễn UTF-8, mỗi ký tự được biểu diễn bởi một chuỗi từ một đến sáu byte, số byte biểu diễn tùy thuộc vào giá trị mã của ký tự, như mô tả trong bảng 2.1 dưới đây [10]:
Giá trị mã của ký tự
trong bộ mã Unicode
Bảng 2.1 Cách biểu diễn ký tự Unicode dạng UTF-8
Cột bên trái là các khoảng giá trị mà ký tự có mã thuộc khoảng giá trị nào thì sẽ được biểu diễn bởi chuỗi byte có dạng như trong cột bên phải ở hàng tương ứng Theo đó, một ký tự trong bộ mã ASCII sẽ được biểu diễn bởi 1 byte mà bit lớn nhất (most significant bit) có giá trị là 0, và 7 bit sau chính là giá trị nhị phân của mã ký tự đó trong ASCII
Các ký tự khác có giá trị lớn hơn 0x0000007F thì sẽ được biểu diễn bởi một chuỗi gồm từ 2 đến 6 byte, tùy theo giá trị mã của chúng, với byte lớn nhất (byte đầu tiên) luôn bắt đầu bởi một chuỗi bit mang giá trị 1 theo sau là một bit mang giá trị 0, và các byte còn lại luôn bắt đầu bởi một bit mang giá trị 1 theo sau là một bit mang giá trị 0
Số các bit đầu mang giá trị 1 trong byte đầu tiên của chuỗi cho biết chuỗi byte biểu diễn của ký tự gồm bao nhiêu byte Và các dấu x trong chuỗi byte khi nối lại với nhau, theo thứ tự, sẽ chính là giá trị nhị phân của mã Unicode của ký tự
Trang 1511100010 10001001 10100000, tức là 0xE2 0x89 0xA0
Thuận lợi khi dùng mã Unicode là các chữ cái tiếng Việt đã được đưa vào bộ mã Unicode trong nhóm La tinh 1 và được Microsoft hỗ trợ trong các phiên bản Windows kể từ Win98 về sau, và các phiên bản Internet Explorer 5 về sau
Vi vậy, dùng browser Internet Explorer 5 trở lên trong môi trường Windows 98, hoặc mới hơn, thì không cần cài đặt thêm font gì mà vẫn xem được đúng chữ Việt
Đối với Netscape Navigator thì Unicode được xem là dạng dữ liệu mặc nhiên dùng cho những xử lý bên trong chương trình, dữ liệu bên ngoài sẽ được chuyển sang dạng này để xử lý rồi sau đó lại được chuyển trở lại dạng ban đầu để kết xuất
2.2 Mô tả sơ lược về ngôn ngữ HTML và XML
HTML ( viết tắt từ HyperText Markup Language ) là ngôn ngữ cơ bản và phổ thông nhất, hiện được dùng trong hầu hết các trang web trên Internet, và chính HTML là phương tiện thuận tiện để liên kết các trang web với nhau, mà khi xem, người duyệt web có thể chuyển từ trang web này sang trang web khác mà không cần quan tâm đến địa chỉ của các trang web đến từ đâu
Nền tảng của HTML là SGML (Standard Generalized Markup Language) là một ngôn ngữ markup tổng quát hóa, hay nói cách khác đó là một tập hợp các chuẩn để phát triển các ngôn ngữ dạng markup
HTML là một ngôn ngữ khá dễ sử dụng, nhờ vào cấu trúc cú pháp đơn giản và dễ hiểu Tập lệnh HTML không có những lệnh điều khiển, tính toán hay xử lý dữ liệu Ngoài một số lệnh để tạo menu dạng danh sách, còn lại hầu hết là những lệnh cho hiển thị văn bản, hình ảnh và cách thức bố trí, hiển thị chúng trên màn hình
Các câu lệnh trong HTML thường được gọi là những thẻ (tag) và cấu trúc các thẻ luôn được bắt đầu bằng một thẻ mở có dạng <tên thẻ>, và kết thúc bằng một thẻ đóng có dạng </tên thẻ> ( mặc dù vậy, đối với một số thẻ, để cho đơn
Trang 16
Về cú pháp, các câu lệnh HTML luôn có cấu trúc khối Trong một trang HTML, các câu lệnh luôn được đặt trong một khối bao bọc bởi hai thẻ <html> và
</html> Bên trong khối <html>-</html> này lại bao gồm hai khối
<head>-</head> và <body>-</body> Đây là hai khối bắt buộc phải có trong bất kỳ trang html nào Phần head của trang web cung cấp những thông tin ban đầu về trang web đó, trong khi đó phần body của trang web chứa nội dung thực sự của trang web Những gì sẽ hiển thị trên trang web được mô tả trong phần body Phần văn bản nằm trong khối body, và không nằm trong khối nào khác, sẽ được hiển thị trên trang web Nhưng để có thể điều chỉnh font, màu và cỡ chữ của nội dung văn bản, HTML có quy định một số thẻ chỉnh dạng như <style>, <font> nằm trong khối body, và phần văn bản nằm trong các khối style và font (trong khối body) cũng sẽ được hiển thị trên trang web
Trong phần head của một trang HTML, có thể có những thẻ như thẻ
<meta>, thẻ <style>, thẻ <font> và thẻ <title>
Thẻ <meta> thường dùng để khai báo về format của trang, trong đó có hai thuộc tính thường được dùng là content và charset Thuộc tính content cho biết trang HTML được tạo ra bằng chương trình nào, thuộc thể loại nào (text/html, text/css, xml ), và thuộc tính charset cho biết bảng mã sử dụng là bảng mã nào
Thông thường, các trang HTML có dạng text/html Một số trang chỉ dùng để chứa những thông tin định dạng cho các trang web khác thì có dạng text/css Một số trang khác được viết bằng XML, một dạng mở rộng của HTML, thì sẽ được khai báo là xml Đối với option charset, các giá trị thường gặp là user-defined (người xem sẽ tự chọn một bộ mã thích hợp qua các setting của browser), ISO-8859-1 (các ký tự thuộc nhóm latinh 1), và UTF-8 (mã Unicode)
Thẻ <style> và thẻ <font> cung cấp những thông tin về hình thức của các dòng văn bản sẽ hiển thị trên trang web, như font chữ, cỡ chữ, màu, in nghiêng,
in đậm, gạch dưới Trong HTML, chúng ta có hai cách để chỉnh dạng các câu văn bản là dùng thẻ <style> hoặc thẻ <font> Nhưng thẻ <style> có những thuộc tính có thể dùng cho các đối tượng khác (như hình ảnh) chứ không chỉ dùng cho văn bản, còn thẻ <font> chỉ có thể áp dụng cho văn bản Ngoài ra, thẻ <style>
Trang 17trang web trên web site mà chỉ cần thay đổi tập tin css
Thẻ <style> và <font> đều có thể khai báo trong head hay trong body, nhưng nếu khai báo trong <head> sẽ có tác dụng cho toàn trang web, còn nếu khai báo trong body thì chỉ có tác dụng cho đoạn văn bản nằm trong khối của thẻ Các thuộc tính thường dùng trong thẻ <style> là font-family, font-face, font-color, font-size để xác định font chữ, màu và cỡ chữ Các thuộc tính thường dùng cho thẻ font là face, color và size
Thẻ <font> cũng khác với thẻ <style> trong cách khai báo các thuộc tính Các thuộc tính của thẻ <style> được đặt trong một thẻ <option> ngay sau thẻ
<style>, còn các thuộc tính của thẻ <font> được đặt ngay trong thẻ <font> Điều này có ý nghĩa đặc biệt khi chúng ta phải phân tích cú pháp của hai loại thẻ này để tìm xem font chữ được sử dụng là font gì
Thẻ <title> được dùng để khai báo tên tiêu đề của trang web Tiêu đề của trang web sẽ là tiêu đề của cửa sổ hiển thị trang web
Trong khối head, chúng ta sẽ đặc biệt quan tâm đến thẻ <meta>, thẻ
<style> và thẻ <font>
Trong khối body của trang web thường có những thẻ như <frame>, <list>,
<LI>, <TD>, <TR>, <A>, <H1>, <H2>, ,<H6>, <IMG>, <style>, <font> Trong đó, thẻ <frame> dùng để chia trang web ra nhiều phần, mỗi phần là một trang web riêng biệt; thẻ <list> và <LI> dùng để tạo menu dạng danh sách; thẻ
<TD> và <TR> dùng để tạo bảng trong trang web; thẻ <A> dùng để tạo một liên kết đến một trang web khác; <H1>, ,<H6> để tạo ra 6 cấp tiêu đề; thẻ <img> dùng để đưa hình ảnh vào trang web; thẻ <style> và <font> dùng để chỉnh dạng một đoạn văn bản
Trong đề tài này, chúng ta chỉ cần quan tâm đến các thẻ tạo văn bản trong trang web và các thẻ chỉnh dạng văn bản
Ngoài những trang web viết bằng ngôn ngữ HTML, một số trang web khác được viết bằng XML ( Extended Markup Language ), là một dạng mở rộng của
Trang 18sẵn và không thể thay đổi hay bổ sung Và bởi vì các tên thẻ do người lập trình đặt ra nên một trang XML thường có kèm theo một tập tin DTD ( Data Type Definition ) để định nghĩa các thẻ, và một tập tin CSS ( Cascade Style Sheet ) Nói chung, XML cũng tương tự như một ngôn ngữ macro trên HTML
Một dạng đặc biệt của XML là XUL ( XML-based User Interface Language ) là một ngôn ngữ cho phép người lập trình thay đổi giao diện của trình duyệt [9] Ngôn ngữ này do hãng Netscape phát triển, và do đó các trình duyệt Nescape Navigator, hay Mozilla đều hỗ trợ ngôn ngữ này Vì vậy, đây là một phương tiện mạnh và rất thuận tiện cho người lập trình
Nhiều nhà lập trình đã bỏ nhiều công sức để viết những ứng dụng trên web tích hợp vào browser bằng cách dùng DHTML, nhưng công việc trở nên phức tạp và kết quả đạt được cũng không mang tính portable Trong khi đó, công việc sẽ trở nên dễ dàng và kết quả cũng mang tính khả chuyển nếu dùng XUL để thay thế DHTML [9]
Vì vậy, ưu điểm của XUL là có khả năng tạo một giao diện mới cho browser bằng cách sửa đổi hay thêm bớt các control trên browser, thuận lợi cho việc đặc thù hóa trình duyệt cho phù hợp với những yêu cầu riêng, hay trong việc xây dựng các ứng dụng tích hợp vào trình duyệt Hơn nữa, kết quả lại có thể sử dụng trong nhiều môi trường hệ điều hành
Ngoài ra, XUL cũng được hổ trợ bởi nhiều công nghệ khác trong Mozilla như :
- XBL (Extensible Bindings Language) : là một ngôn ngữ markup, cho phép người lập trình định nghĩa những control riêng sử dụng trong XUL
- Overlays : là cơ chế nạp chồng cho phép người lập trình có thể nạp chồng các tập tin overlays chứa các thông tin về giao diện của browser Overlays có thể được dùng để thay đổi một phần giao diện mà không cần định nghĩa lại những gì đã có sẵn
Trang 19phép tích hợp các thư viện ngoại trú vào các ứng dụng XUL
Trong Mozilla, hầu hết các menu, cửa sổ, hộp thoại giao tiếp với người sử dụng đều được thực hiện bằng XUL với cơ chế Overlays Bằng cách này người lập trình chỉ cần tạo những tập tin overlays chứa những thông tin cần thiết để cấu hình lại browser, sau đó khai báo tập tin này bằng dòng lệnh như sau :
<?xul-overlay href=” ”?>
Trong ngôn ngữ XUL có 4 nguyên tắc về cú pháp cần tôn trọng là : [9]
• các sự kiện (event) và các thuộc tính luôn được viết bằng chữ thường
• các thẻ khai báo các đối tượng trên giao diện ( menu các loại ) đều phải kết thúc bằng một thẻ đóng </tên thẻ>
• hằng chuỗi phải được đặt trong dấu nháy kép
• tất cả các thuộc tính trong một thẻ đều phải được gán trị
Khả năng của XUL cho phép người lập trình có thể tạo thêm hay điều chỉnh các cửa sổ, hộp, nút, và menu các loại, trên giao diện của browser Tuy nhiên, trong đề tài này chúng ta chỉ sử dụng XUL để tạo thêm một menu pop-up trên thanh menubar
Để tạo thêm một menu pop-up trên thanh menubar của browser, trong phần sau chúng ta sẽ sử dụng 3 thẻ <menu>, <menupopup> và <menuitem>, kết hợp với các đoạn Javascript để xây dựng những hành động kèm theo khi một option được chọn
Trang 20
III Phân tích và tìm hiểu mã nguồn Mozilla
Với nội dung của luận án như đã trình bày trong chương đầu, hướng giải quyết của chúng ta là dựa vào mã nguồn mở hiện có của trình duyệt web Mozilla, và bổ sung thêm chức năng tự động phát hiện những đoạn văn tiếng Việt trong trang web, sau đó xác định bộ mã tiếng Việt mà đoạn văn bản trên sử dụng, và tự động chuyển mã cho đoạn văn này sang Unicode để Mozilla có thể hiển thị đúng nội dung chữ Việt
Do đó, bước đầu tiên chúng ta cần phải tìm hiểu, phân tích mã nguồn Mozilla để nắm được cơ chế hoạt động cụ thể của trình duyệt, đặc biệt là cơ chế hoạt động của bộ phân tích và giải mã ( parser ) của trình duyệt, nhằm có thể xác định được chúng ta cần đưa thêm những chức năng mới vào đâu trong bộ mã nguồn cho thích hợp nhất mà không làm ảnh hưởng đến toàn bộ các chức năng khác của Mozilla
Mã nguồn được chọn để sử dụng trong luận án này là mã nguồn 0.9.8 được download từ web site www.mozilla.org trên Internet, đây là phiên bản mới nhất vào thời điểm luận văn này bắt đầu được thực hiện Phiên bản mới nhất của mã nguồn Mozilla trên Internet hiện nay có thể đã lên đến hơn 1.3.1 Tuy nhiên, về mặt ý tưởng thì mã nguồn Mozilla-0.9.8 và Mozilla-1.3.1 cũng không khác nhau là mấy
Mozilla-3.1 Tìm hiểu về cơ chế hoạt động của Mozilla
Trước tiên, chúng ta sẽ tìm hiểu phần cấu trúc hạ tầng của Mozilla Những bộ phận nền tảng của Mozilla có thể kể là XPCOM (Cross Platform Component Object Model), XPConnect và XPFE (Cross Platform Front End, hay còn gọi là XPTool Kit) Chúng ta sẽ đề cập đến XPCOM và XPConnect trước, vì tầm quan trọng của chúng Hơn nữa, vì hai thành phần này có quan hệ rất khắng khít với nhau nên ta sẽ không tách ra hai phần riêng để nói về hai thành phần này
Mozilla là một dự án mở rộng ở tầm cỡ khá lớn, được đặt dưới sự quản lý của môt tổ chức cũng có tên là Mozilla (Mozilla vừa là tên của dự án, vừa là tên của tổ chức quản lý dự án) với địa chỉ trên Internet là www.mozilla.org Mục
Trang 21đích của dự án này là xây dựng một trình duyệt web có thể chạy trên mọi môi trường hệ điều hành Mã nguồn Mozilla chính là nền tảng để xây dựng nên browser Netscape Navigator Bắt đầu vào đầu năm 1998, hãng Netscape đã đưa bộ mã nguồn của Netscape Navigator lên mạng và từ đó, trở thành một mã nguồn mở dưới sự quản lý của tổ chức Mozilla Mã nguồn Mozilla bao gồm hàng triệu câu lệnh do nhiều người viết, vì vậy xâm nhập vào cũng như quản lý mã nguồn Mozilla khó có thể tránh khỏi sai sót Chính vì thế, bản thân Mozilla chưa phải là một sản phẩm hoàn hảo Mã nguồn Mozilla vẫn còn có lỗi, và đang tiếp tục được sửa đổi, bổ sung để hoàn thiện Một số mô đun trong Mozilla hiện nay đã lỗi thời và không còn được sử dụng
Toàn bộ mã nguồn Mozilla được viết trên tinh thần độc lập môi trường, theo hướng đối tượng và được thiết kế để chạy trên máy khách (client) Ngôn ngữ lập trình được dùng chủ yếu trong Mozilla là C và C++ Một số ít chương trình được viết bằng Javascript và XUL
Mặc dù, C và C++ là ngôn ngữ lập trình biên dịch (compiled) trong khi Javascript là ngôn ngữ lập trình phiên dịch (interpreted), nhưng Mozilla lại được thiết kế theo hướng kết hợp C++ và Jacascript để chạy lúc runtime nhờ vào một thành phần môđun (modular component) của Mozilla có tên là XPConnect Khi Mozilla được khởi động, bộ phận lõi viết bằng C/C++ sẽ được chạy trước Sau đó, XPConnect được kích hoạt và cho phép các script JavaScript có thể chạy lúc runtime XPConnect đảm nhận công việc trao đổi thông tin giữa C/C++ và Javascript
Cũng cần nói thêm rằng, các script JacaScript khi chạy không thể truy xuất đến các đối tượng bên trong của Mozilla, ngoại trừ những đối tượng nằm trong DOM ( Document Object Model) Hầu hết các script JavaScript được dùng để viết các chương trình con liên kết với các event trong giao diện với người sử dụng Các chương trình con này sẽ được kích hoạt khi có một tác động nào đó của người sử dụng lên các control của browser
Mã nguồn Mozilla được viết tuân theo những ràng buộc của kỹ thuật lập trình hướng đối tượng (Object Oriented Programming) Do đó, Mozilla được viết theo từng thành phần mô đun (modular component), trong đó quyền truy cập đến các biến được phân định rõ ràng tùy theo chúng được khai báo public, protected hay private Chỉ có các biến được khai báo là public của một lớp mới có thể được
Trang 22truy xuất từ các hàm trong các lớp khác, còn các biến được khai báo là protected thì chỉ có thể truy xuất qua các hàm member của chính lớp đó mà thôi
Hơn thế nữa, các hàm hoặc biến trong mỗi component chỉ có thể truy xuất bởi các hàm bên ngoài component đó thông qua các giao diện (interfaces) theo
cơ chế COM (Component Object Model) Mỗi một component thường có thể được giao tiếp bằng nhiều giao diện, và các giao diện đều được xây dựng dựa trên một giao diện cơ sở có tên là nsISupport
Mô hình COM trong Mozilla có tên là XPCOM (Cross Platform Component Object Model) vì nó có tính độc lập môi trường XPCOM có thể được xem là bộ khung để phát triển các ứng dụng đa môi trường XPCOM sử dụng một tập hợp các thư viện, trong số đó, những thư viện cần thiết, tại từng thời điểm, sẽ được load vào bộ nhớ để quản lý các component
XPCOM dựa vào các giao diện để quản lý các component, và công việc này được giao cho một môđun có tên là XPCOMManager Chức năng của XPCOM là xác định xem ứng với mỗi component sẽ có những giao diện nào, và thực hiện việc chuyển đổi từ giao diện này sang giao diện khác khi cần thiết
XPCOM chính là nền tảng của Mozilla vì chính XPCOM là chất keo dính liên kết các component trong Mozilla Hay nói cách khác, Mozilla là một ứng dụng viết trên XPCOM Và XPConnect có thể xem là một lớp bên trên của XPCOM, có chức năng trao đổi thông tin giữa các component viết bằng C/C++ và JavaScript engine dựa vào các tập tin type library mô tả các giao diện (được tạo ra bởi compiler XPIDL)
XPCOM có nguồn gốc từ CORBA, là một môi trường, được xây dựng bởi nhóm OMG (Object Management Group), trong đó có áp dụng mô hình COM và sử dụng ngôn ngữ định nghĩa giao diện IDL
Các môi trường mà XPCOM hỗ trợ bao gồm : Microsoft Windows (mọi phiên bản), Linux, HP-UX, AIX, Solaris, OpenVMS, MacOS và BSD Hiện nay, một số ứng dụng đã được xây dựng để chạy trên XPCOM có thể kể là Komodo, Chatzilla, MozInvaders (game), Xultris (game), Jabberzilla, Netscape Navigator và Mozilla
Trang 23Nhờ có XPConnect nên các component trong XPCOM có thể được viết hoàn toàn bằng Javascript, và một môđun viết bằng C++ vẫn có thể gọi đến một component viết bằng JS, và ngược lại [18]
XPConnect thực hiện công việc trên nhờ vào hai môđun là JS2CPPProxy và CPP2JSProxy [18] JS2CPPProxy cho phép một chỉ thị Javascript truy cập đến một đối tượng C++ XPCOM Công việc của JS2CPPProxy là dựa vào những giao diện của Javascript, chỉnh dạng các tham số trong các method của giao diện và chuyển chỉ thị gọi đến các đối tượng C++ XPCOM Công việc của đối tượng CPP2JSProxy cũng tương tự như vậy, nhưng ngược lại, CPP2JSProxy đảm nhận việc “bao bọc” các đối tượng Javascript lại để tương thích với các lệnh gọi từ C++ Để viết code cho hai môđun nói trên, một vài chỗ cũng cần phải dùng đến ngôn ngữ assembler
Bên cạnh XPConnect còn có những XPJS component, là những môđun trong XPCOM, đảm nhận việc khởi tạo và đăng ký cho các đối tượng Javascript Đây là một công việc hạ tầng cơ sở được thực hiện một cách độc lập, không phụ thuộc vào nội dung của trang web
Các XPJS component được chứa trong các tập tin js, và trong mỗi component này đều có định nghĩa 4 hàm đặc biệt là NSRegisterSelf, NSGetFactory, NSUnregisterSelf và NSCanUnload [20] Mỗi một tập tin js đảm nhận việc hiện thực cho một hoặc nhiều component JavaScript Các tập tin js này được load và đăng ký dưới sự quản lý và trợ giúp của một môđun có tên là XPJSManager, hoạt động như một đơn vị trung gian giữa XPCOMManager và JavaScript engine
Quá trình tự động đăng ký của một XPJS component được diễn ra như sau Đầu tiên, XPJSManager load tập tin js vào một môi trường JS, và cho chạy script ở level cao nhất để thực hiện những gì mà một quá trình khởi động yêu cầu Sau đó, XPJS sê gọi hàm NSRegisterSelf với tham số là tên tập tin js Tiếp theo, component này sẽ gọi những method trong bản thân nó để đăng ký với XPJSManager và trở thành một factory của một hoặc nhiều lớp Khi đó, XPJSManager sẽ lưu thông tin vào bảng đối chiếu giữa các classid và tên các tập tin js
Trang 24Từ khi đó, nếu có một yêu cầu tạo một đối tượng thuộc một lớp nào đó, thì hàm NSGetFactory trong XPJSManager sẽ được gọi, hàm này sẽ tra tìm classid của lớp được yêu cầu để biết được tên tập tin js tương ứng và load tập tin này vào bộ nhớ (nếu như trước đó chưa có trong bộ nhớ) Tiếp theo, XPJSManager sẽ gọi hàm NSGetFactory trong lớp đó Hàm này sẽ trả về một đối tượng JavaScript và XPConnect sẽ chuyển đối tượng này thành một đối tượng XPCOM
Nếu so sánh XPCOM và Microsoft COM, chúng ta thấy có một số điểm giống nhau Cốt lõi của mô hình COM chính là khái niệm về giao diện Việc sử dụng các giao diện đã mang đến cho hệ thống một sự linh động, mềm dẻo, bởi vì phần hiện thực của một component có thể tự do thay đổi khi cần thiết mà không gây ảnh hưởng cho cả hệ thống ( Trong giai đoạn ban đầu của XPCOM, việc thay đổi trong phần định nghĩa của giao diện vẫn thường xảy ra Tuy nhiên, khi đến giai đoạn chín chắn thì các giao diện cần được giữ cố định Hiện nay, những giao diện nào được ghi chú thích @status FROZEN trong tập tin idl thì sẽ không được phép thay đổi )
Các giao diện trong cả hai mô hình Microsoft COM và XPCOM đều được xây dựng dựa trên một giao diện cơ sở, là nsISupports trong XPCOM và IUnknown trong Microsoft COM Trong giao diện này có định nghĩa 3 hàm thành viên cơ bản là : QueryInterface(), AddRef(), và Release() [13] [14]
Hàm QueryInterface() dùng để gọi đến một giao diện để cung cấp phần hiện thực của một đối tượng, giá trị trả về là một con trỏ chỉ đến một giao diện AddRef() dùng để theo dõi số các tham chiếu đến một đối tượng Release() dùng để giải phóng bộ nhớ cho biến con trỏ trả về từ hàm QueryInterface()
Để tham chiếu đến một giao diện trong XPCOM, có thể dùng hai cách : dùng UUID của giao diện, hoặc dùng contract ID (được gọi là ProgID trong Microsoft COM) UUID (Universally Unique Identifier), mã nhận dạng của một giao diện, là một chuỗi ký tự gồm 16 byte Và contract ID là một chuỗi ký tự có dạng:
@<internetdomain>/module[/submodule[ ]];<version>
[?<name>=<value>[&<name>=<value>[ ]]]
Trong một giao diện, ngoài những hàm và dữ liệu thành viên, còn có thể có những thuộc tính (attribute), và những thuộc tính này có thể được truy xuất bởi
Trang 25những script Javascript Tất nhiên, loại dữ liệu của những thuộc tính này sẽ bị giới hạn trong phạm vi mà Javascript có thể truy xuất được
Các giao diện trong XPCOM được định nghĩa bởi một ngôn ngữ riêng, hơi khác với IDL của Microsoft và CORBA, có tên là XPIDL (Cross Platform Interfaces Definition Language) Chức năng chính của XPIDL là biên dịch các tập tin idl thành các tập tin InterfaceInfo (một dạng tương đương với các tập tin typelib trong MS COM, nhưng có tính độc lập môi trường), trong đó chứa những bảng mô tả các giao diện, các hàm thành viên và các tham số Các bảng này được lập chỉ mục để có thể truy xuất nhanh Một bảng chính sẽ liên kết các UUID với địa chỉ offset của tập tin InterfaceInfo tương ứng
Các tập tin InterfaceInfo có phần tên mở rộng là xpt, và phần header của các tập tin này có cấu trúc được mô tả như sau [13]:
TypeLibHeader {
char magic[16];
uint8 major version;
uint8 minor version;
uint16 num interfaces;
Trang 26Mọi chi tiết về các tập tin InterfaceInfo sẽ được che dấu trong các đối tượng nsIInterfaceInfoFactory và nsIInterfaceInfo nsIInterfaceInfoFactory là một đối tượng factory có chức năng tạo ra một đối tượng nsIInterfaceInfo (chứa các thông tin về một giao diện) khi cần truy xuất đến một giao diện Các đối tượng nsIInterfaceInfo có thể được dùng chung, và có biến đếm để theo dõi số giao diện đang truy cập đến Cơ chế đẳng cấp trong giao diện cũng được duy trì cho các đối tượng nsIInterfaceInfo Do đó, đối tượng nsIInterfaceInfo ứng với một giao diện con sẽ được tạo một mối liên kết đến đối tượng nsIInterfaceInfo của giao diện mẹ
Ngoài chức năng biên dịch các tập tin idl, XPIDL còn có chức năng tự động tạo ra các tập tin header h của C/C++ để mô tả các giao diện CORBA và Microsoft IDL compiler cũng có tính năng tương tự, nhưng không có tính độc lập môi trường
Mỗi khi có một tham chiếu của một giao diện đến một đối tượng, thì hàm AddRef() (trong giao diện chuẩn nsISupports) cần được gọi để làm tăng thêm giá trị của counter bên trong đối tượng lên 1 Và mỗi khi một tham chiếu đến đối tượng được giải tỏa, thì hàm Release() cần được gọi để làm giảm giá trị counter xuống 1 Đến khi nào giá trị của counter bằng 0, thì có nghĩa là không còn tham chiếu nào đến đối tượng đó nữa và khi đó đối tượng này có thể và cần được hủy để giải tỏa bộ nhớ
Việc theo dõi số tham chiếu đến từng đối tượng là một công việc khá phiền toái cho người lập trình, nhưng người lập trình cần phải thực hiện để có thể biết được lúc nào cần phải hủy các đối tượng không còn cần nữa nhằm tránh tình trạng rò rỉ bộ nhớ Điều đó có nghĩa là trong chương trình, ứng với mỗi lệnh gọi hàm AddRef() thì phải có một lệnh gọi hàm Release() tương ứng Nhưng thường thì lệnh gọi hàm AddRef() được tự động đưa vào trong hàm QueryInterface(), vì vậy vấn đề còn lại là kiểm tra mỗi một lệnh gọi QueryInterface() phải có một lệnh gọi hàm Release() tương ứng Nếu thừa hoặc thiếu một số các hàm Release() có thể dẫn đến những lỗi không lường trước được
Để tránh những trường hợp có thể gây ra lỗi như trên, XPCOM đưa ra một biện pháp là dùng một kiểu con trỏ thông minh được định nghĩa trong XPCOM là nsCOMPtr [14] nsCOMPtr được định nghĩa là một template, dùng như một con
Trang 27trỏ chỉ đến địa chỉ của một giao diện, và nó sẽ tự động thực hiện việc giải phóng giao diện ra khỏi bộ nhớ khi mà bản thân con trỏ được giải tỏa, hoặc khi con trỏ được chuyển đến địa chỉ khác Đây là một ưu điểm của XPCOM so với MS COM
Một điểm khác nhau nữa giữa Microsoft COM và XPCOM là Microsoft COM hỗ trợ kỹ thuật proxy component rất tốt, vì MS COM được thiết kế để giao tiếp với nhiều dạng ứng dụng, kể cả những ứng dụng được chạy như một chương trình riêng biệt và trên một máy khác trên mạng Trong khi đó, XPCOM được thiết kế để hỗ trợ các component ở phạm vi một ứng dụng, do đó XPCOM chỉ cung cấp những dịch vụ proxy cho phép các luồng có thể dùng chung một component XPCOM không cho phép truy xuất đến các component ở các máy khác trên mạng
Hơn nữa, các component trong Microsoft COM và XPCOM cũng không tương thích và không giao tiếp với nhau được, vì XPConnect không hỗ trợ Microsoft COM Giao diện IDispatch của MS COM không thể dùng được trong XPCOM Các tập tin typelib tạo ra bằng Microsoft IDL không thể dùng được trong XPCOM, bởi vì các đối tượng không được khai báo bằng XPIDL sẽ có giá trị trả về không đúng kiểu quy định của XPCOM [14] [15]
Vì vậy, cần bổ sung thêm những đoạn code làm vỏ bọc để có thể nhúng chúng vào nhau Mozilla đã thực hiện chuyện này, vì thế Mozilla có thể chạy trên Windows như một MS ActiveX control, trong khi đó bên trong browser vẫn dùng các component của XPCOM
Ngoài hai thành phần XPCOM và XPConnect đã được đề cập trên đây, trong Mozilla còn có một thành phần cơ bản khác là XPFE (Cross Platform Front End hay còn gọi là XPTool Kit) Môđun này cung cấp những công cụ để tạo các đối tượng trên cửa sổ giao diện của browser như hộp thoại, các loại nút điều khiển, thanh trượt, thanh tiến trình, thanh công cụ, danh sách, các loại menu, cửa sổ, cấu trúc cây, bảng chọn màu, hộp tooltip Các môđun này thường được viết bằng XUL và JavaScript
Trước khi kết thúc phần này, chúng ta cũng cần nhắc lại đôi chút về khái niệm mô hình DOM (Document Object Model) [22]
Trang 28DOM là một tập hợp các giao diện, không phụ thuộc ngôn ngữ, dùng cho các document HTML và XML Nói rõ hơn, DOM là một API cho phép người lập trình có thể thêm, bớt, hay thay đổi nội dung của các document HTML và XML DOM cũng cung cấp các phương tiện để hiển thị các đối tượng trong document ra màn hình Vì thế, DOM là phương tiện liên kết các trang web và các ngôn ngữ lập trình
Điểm đặc biệt của DOM là được thiết kế trên tinh thần độc lập ngôn ngữ,
do đó DOM có thể được hiện thực bằng bất kỳ ngôn ngữ nào Tuy nhiên, thông thường thì DOM được hiện thực bằng JavaScript, và JavaScript thường được dùng để giao tiếp với DOM Thế nhưng Mozilla đã sử dụng DOM bằng cả C++ và JavaScript
DOM đã được chuẩn hóa bởi các tiêu chuẩn của World Wide Web Consortium, và ngày nay các browser chính đều phải tuân thủ nghiêm ngặt các tiêu chuẩn này, nhờ vậy dựa vào DOM có thể xây dựng các ứng dụng web không phụ thuộc vào browser
Những giao diện chính được định nghĩa trong DOM gồm có :
- DOM : là một giao diện cung cấp các method “tĩnh” (instance independent), tức là khi một ứng dụng trên client dùng đến DOM thì không cần thiết phải xác định xem đối tượng DOM ở đâu trong khi vẫn có thể truy xuất trực tiếp đến các method của lớp DOM
- document context: giao diện này thể hiện những thông tin không liên quan trực tiếp đến nội dung của trang web, nhưng liên quan đến tập tin chứa trang web, chẳng hạn những thông tin nằm trong header, hay địa chỉ của trang web
- document : một đối tượng document thể hiện nội dung của toàn bộ trang web, đây là đối tượng gốc (root) trong mô hình cây của trang web, từ đối tượng này có thể xây dựng cũng như truy xuất đến các đối tượng thành phần trong nội dung trang web như các Element, Text, Comment, PI
- node : là đối tượng chủ yếu nhất trong mô hình cây của trang web, biểu hiện một nút trong cây cấu trúc Một nút có thể có một hay nhiều nút con
- element : là một loại node thường gặp nhất trong cấu trúc cây của trang web element bao gồm chính bản thân nó và cả các nút con nằm trong nó
- attribute : thể hiện một thuộc tính của một element
Trang 29- attributelist : danh sách các thuộc tính của một element
- text : thành phần văn bản trong một thẻ, là một đối tượng con của một element
- comment : nội dung của một thẻ comment
- PI (processing instruction) : nội dung của một chỉ thị, tức là tất cả những
gì nằm giũa <? và ?>
3.2 Mô tả tổng quát quá trình hiển thị một trang web trong Mozilla
Khi người xem đưa vào browser một chỉ thị tải về một trang web, các script JavaScript sẽ được thực hiện, và thông qua XPConnect, chỉ thị này được truyền tới đối tượng nsWebShell nsWebShell sẽ gọi hàm DoLoadURL để thực hiện việc tải về trang web ở địa chỉ mà người xem đã chọn
Hàm DoLoadURL sẽ gọi đến giao diện nsIDocumentLoader Đối tượng nsDocumentLoader, trong giao diện nsIDocumentLoader, sẽ gọi hàm NS_OpenURI với tham số là địa chỉ của trang web Sau đó, một thư viện các dịch vụ trên mạng, có tên là Necko, sẽ kiểm tra tham số địa chỉ của trang web để xác định protocol làm việc là protocol nào, và gọi đến giao diện nsIProtocolHandler để yêu cầu cấp phát một kênh nsHTTPChannel Đối tượng này sẽ giữ vai trò kết nối với server và là nguồn cung cấp dữ liệu đầu vào cho browser
Sau đó, nsHTTPChannel sẽ gọi hàm OnStartRequest trong đối tượng nsDocumentLoader Và khi đó, nsDocumentLoader sẽ tìm đến giao diện nsIDocumentLoaderFactory để tạo ra một factory dành cho text/html document (nếu như đây là một tập tin html) Factory này sẽ tạo ra đối tượng nsContentViewer và đối tượng nsHTMLDocument Hai đối tượng sẽ được liên kết với nhau qua hàm BindToDocument() Đồng thời, nsContentViewer cũng đươc nhúng vào nsContentViewerContainer trong nsWebShell
Đối tượng nsHTMLDocument sẽ tạo ra một nsParser để thực hiện việc phân tích giải mã, đồng thời đối tượng nsStreamListener cũng được tạo ra và liên kết với kênh nsHTTPChannel để ngóng chờ dữ liệu
nsWebShell (DoLoadURL) nsIProtocolHandler
SERVER
(URL)
Trang 30nsHTMLDocument cũng tạo ra một đối tượng nsContentSink để chứa các token, sinh ra từ parser trong quá trình phân tích giải mã nsContentSink sẽ liên kết với nsParser và nsHTMLDocument trong suốt quá trình giải mã Sau đó, nsParser thực hiện việc phân tích giải mã, và chuyển các token thành các đối tượng nsParserNode trong nsContentSink
nsIDTD
Hình 3.1 Quá trình hiển thị một trang web
Trang 31Trong quá trình thực hiện, nsParser sẽ nhận dữ liệu từ nsStreamListener theo từng block 8 KB Dữ liệu sau khi được giải mã sẽ được tạo thành các nsParserNode và được đặt vào trong nsContentSink Công việc được tiến hành từng block một cho đến block cuối cùng hoặc đến khi parser tạm thời bị nghẽn Khi đó, quá trình sẽ chờ đến lúc hết nghẽn để tiếp tục xử lý block đang làm dở dang
Sau khi quá trình parsing kết thúc, nsContentSink sẽ tạo các nút nsContent trong mô hình cây của trang web, bằng cách gọi các hàm NS_NewHTMLxxxxElement() (xxxx sẽ được thay bằng tên của các thẻ trong HTML) Những nút này được hiện thực qua giao diện nsIHTMLContent và các giao diện DOM tương ứng Hàm AppendChild() trong nsIContent được dùng để tạo thêm các nút trong mô hình cây biểu diễn nội dung trang web
Đối tượng nsPresShell được đăng ký với nsIDocument như là một thành viên quan sát, thuộc lớp nsDocumentObserver, giữ nhiệm vụ thông báo đến nsDocument khi có sự thay đổi trong cấu trúc cây mô hình nội dung của trang web
Mặt khác, đối tượng nsCSSFrameConstructor sẽ tạo ra các frame, thuộc giao diện nsIFrame, theo đúng cấu trúc đẳng cấp trong cấu trúc cây mô hình của trang web Mỗi một nút nsContent sẽ ứng với một hoặc nhiều frame (ngoại trừ các nút không cần display) Bên cạnh đó, các frame cũng bị chi phối bởi các đối tượng nsStyle, cung cấp những thông tin về ngữ cảnh của một frame Một nsStyle có thể ứng với một hoặc nhiều frame
Phân tích giải mã (parsing) là công đoạn đầu tiên trong chuỗi công việc mà browser phải thực hiện để cho hiển thị một trang web lên màn hình Công đoạn này phải thực hiện nhanh, đa năng và phải ổn định bất chấp các dạng lỗi do dữ liệu gây ra
Parsing engine, bộ phân tích giải mã trong Mozilla, được thiết kế để có thể làm việc trên nhiều dạng dữ liệu Trong trường hợp dữ liệu là HTML, Parsing engine sẽ chuyển các thẻ HTML thành một mô hình thể hiện nội dung của trang web theo cấu trúc cây, và sau đó được hiển thị ra màn hình qua giao diện nsIRenderingContext
Trang 32Các bộ phận chính trong Parsing engine gồm có:
1 Scanner : là một môđun cung cấp những dịch vụ truy cập đến các ký tự trong một nguồn dữ liệu đầu vào (input stream) Hơn nữa, scanner sẽ tự động thực hiện việc chỉnh dạng dữ liệu nhập vào cho thích hợp với yêu cầu của các môđun xử lý tiếp theo, đồng thời scanner cũng có thể lướt qua những chuỗi ký tự vô nghĩa
2 Parser: bộ phận parser là môđun đảm trách nhiệm vụ chính trong việc phân tích giải mã Môđun này kiểm soát các hoạt động giao tiếp với các component khác Cơ chế phân tích giải mã có thể được thực hiện một cách linh động không phụ thuộc vào văn phạm của mã nguồn, nhờ vào một môđun có tên là DTD Công việc của parser là chia cắt từng câu lệnh trong mã nguồn ra thành các token Mỗi token là một cụm từ gồm một hoặc nhiều từ trong một câu lệnh của mã nguồn và có cùng một chức năng về mặt cú pháp
3 DTD: là một môđun đảm trách việc phân tích văn phạm cú pháp Mỗi một văn phạm (HTML hay các dạng mở rộng XML) sẽ ứng với một DTD DTD là môđun có thể hiểu được các quy luật văn phạm của ngôn ngữ đang được sử dụng Trong môđun này có định nghĩa các thẻ, các thuộc tính của thẻ và những quy luật về cơ chế lồng nhau của các thẻ Việc tách rời DTD ra thành một component độc lập cho phép parsing engine có thể áp dụng cùng một cơ chế để giải mã cho nhiều dạng mở rộng của html, trong đó xml
4.Content Sink : là một API đơn giản, trong đó có những container, leaf và những node, những đối tượng nsContent để chứa các token được sinh ra từ parser DTD sẽ giao tiếp với Content Sink để xây dựng nên mô hình nội dung của trang web Sau khi quá trình tạo các token của parser đã kết thúc, Content sink sẽ duyệt lại từ token đầu tiên cho đến token cuối cùng (hoặc cho đến khi xuất hiện lỗi) để kiểm tra tính hợp lệ về mặt văn phạm của các token, nhờ vào các thông tin từ DTD Đồng thời, nếu việc kiểm tra văn phạm không có lỗi, quá trình này cũng sẽ tạo ra một mô hình cây biểu hiện nội dung trang web
Sau đây chúng ta sẽ tìm hiểu sự hoạt động kết hợp giữa các thành phần trong bộ phân tích giải mã của Mozilla
Trang 333.3 Mô hình tổng quát việc phân tích & giải mã trong Mozilla
Trang 34Hình trên là mô hình tổng quát về chức năng phân tích và giải mã một trang HTML trong Mozilla
Đối tượng HTMLDocument ( thuộc lớp nsHTMLDocument ) thể hiện toàn bộ nội dung của một trang web Đối tượng này giao tiếp với browser ( được thể hiện bởi các lớp JavaScript nsBrowser và nsNavigation ) qua các giao diện của XPConnect, trong đó có giao diện nsIDocumentCharsetInfo, là một giao diện chứa các thông tin về thuộc tính của trang web Giao diện này sẽ nhận vào thông tin về bộ mã sử dụng, mà người dùng xác định qua các script JavaScript gắn với các thao tác trên các control của browser, và gán cho các biến trong đối tượng HTMLdocument để sau đó được chuyển đến các đối tượng chức năng
Để tiến hành việc phân tích giải mã, đối tượng HTMLDocument sẽ tạo ra đối tượng Parser, thuộc lớp nsParser Đối tượng Parser có hai nhiệm vụ chính là :
Parser
ParserContext
NavDTD
Tokenizer TokenDeque
Scanner ContentSink
•
•
TextToken AttributeToken
EntityToken
Hình 3.2 Mô hình phân tích giải mã trong Mozilla
Trang 35a) Phân tích và chia cắt các câu lệnh trong mã nguồn ra thành từng thành phần đơn vị cú pháp, gọi là các token
b) Cùng với đối tượng ContentSink, để tạo ra mô hình nội dung ( content model ) của một trang web
Đồng thời với việc tạo ra đối tượng Parser, HTMLDocument cũng tạo ra một đối tượng khác là ContentSink Chức năng của đối tượng này là, từ những token được cung cấp bởi đối tượng Tokenizer, xây dựng nên mô hình nội dung của trang web với đầy đủ ý nghĩa về cú pháp
Đến lượt Parser tạo ra một đối tượng khác, đó là đối tượng ParserContext Đối tượng chứa những thông tin bổ sung cho Parser, đó là những thông tin ghi nhận về môi trường, ngữ cảnh hiện thời của một Parser, như ParserCommand ( chỉ thị yêu cầu của Parser, thường là NormalView hoặc SourceView ), DTDMode ( chế độ phân tích, thường là QuirkMode ), MimeType ( thể loại của trang web như html, xml, css ) Những thông tin này được dùng để điều khiển quá trình phân tích giải mã
Lúc này, ParserContext lại cần đến công việc của một đối tượng NavDTD, môđun duy nhất trong bộ phân tích giải mã có khả năng hiểu được văn phạm HTML, và có nhiệm vụ chính là :
a) Cùng với Parser thực hiện việc phân tích các câu lệnh thành những token mang những ý nghĩa riêng về cú pháp và sẽ tương ứng với các đối tượng nsContent trong mô hình nội dung của trang web
b) Theo dõi, kiểm tra các quy luật cú pháp đối với các phần tử HTML ( các đơn vị cú pháp trong HTML )
c) Kiểm soát việc trao đổi dữ liệu giữa hai đối tượng Parser và ContentSink
d) Theo dõi và quản lý việc áp dụng các thẻ quy định kiểu của văn bản (
<style>, <font>, ) thông qua cấu trúc style-stack
Trang 36Tiếp theo, NavDTD sẽ tạo ra, theo yêu cầu của Parser, đối tượng Tokenizer Tokenizer sẽ là nơi cung cấp các token cho quá trình xây dựng mô hình một trang web Các token được phân ra làm nhiều lớp và tùy thuộc vào văn phạm của ngôn ngữ lập trình Đối với HTML, một lớp cơ bản chung cho các token là CTokens, lớp này lại chia ra các lớp con như sau :
a) Lớp StartToken : gồm những thẻ mở, có dạng <tên thẻ>
b) Lớp EndToken : gồm những thẻ đóng, tức là những thẻ có dạng </tên thẻ>
c) Lớp CommentToken : gồm những đoạn ghi chú tức là phần văn bản được kẹp giữa hai chuỗi /* và */, hoặc nằm trên một dòng phía sau chuỗi //
d) Lớp EntityToken : mỗi token là một entity trong HTML, tức là các ký tự Unicode được biểu diễn dưới dạng &#xx x; , trong đó xx x là mã Unicode của ký tự, hoặc dưới dạng &xx x, trong đó xx x là tên alias của ký tự
e) Lớp WhiteSpaceToken : mỗi token là một chuỗi các khoảng trắng liền nhau ( trong HTML cac khoảng trắng không nằm trong chuỗi trực kiện sẽ được bỏ qua không xử lý )
f) Lớp TextToken : bao gồm một đoạn văn bản ( độc lập ) sẽ được hiển thị trên trang web Lớp token này là lớp token mà chúng ta đặc biệt quan tâm, vì đây là đối tượng cho việc chuyển đổi mã tiếng Việt
g) Lớp CDATASectionToken : không cần quan tâm
h) Lớp CMarkupDecIToken
i) Lớp AttributeToken : mỗi token là chuỗi các thuộc tính của một thẻ Loại token này cũng sẽ được chúng ta xét đến trong phần sau
j) Lớp NewLineToken : thẻ xuống dòng
k) Lớp ScriptToken : là những thẻ <Script>
Trang 37l) Lớp StyleToken : gồm những thẻ <Style> quy định kiểu cho đoạn văn bản kết xuất
Trở lại với sơ đồ trên, đối tượng Tokenizer tạo ra các đối tượng Token và đặt vào trong một đối tượng gọi là TokenDeque Đây là nơi quản lý các token theo chỉ số Các token trong TokenDeque sẽ được ContentSink dùng, để thiết lập mô hình cho trang web với đầy đủ các phần head, body, frame
Ngoài ra, Parser cũng còn tạo ra một đối tượng nữa, đó là đối tượng Scanner Đối tượng này, như trong phần trước có đề cập đến, chính là nguồn cung cấp dữ liệu đầu vào cho quá trình phân tích giải mã Đối tượng này sẽ được truy xuất đến bởi Tokenizer để tạo ra các token
Sau đây chúng ta sẽ khảo sát chi tiết hơn về cơ chế hoạt động và quan hệ giữa các đối tượng trong sơ đồ trên
3.4 Khảo sát chi tiết hơn về cơ chế phân tích cú pháp trong Mozilla
Sau khi địa chỉ URL của trang web cần truy cập được xác định trên giao diện của browser, thông tin này sẽ được chuyển cho đối tượng HTMLDocument, tiếp theo đối tượng này cho thực hiện hàm StartDocumentLoad() Công việc của hàm này là tạo ra các biến đối tượng cần thiết ( như Parser, ContentSink, httpChannel ), sau đó gọi đến Parser và yêu cầu thực hiện hàm Parse() Chức năng của Parse() là khởi tạo một số đối tượng như ParserContext, Scanner Sau
Trang 38đó, vì Parser là một lớp con của lớp StreamListener, nên hàm OnDataAvailable() _ một member của StreamListener _ cũng được định nghĩa trong Parser, hàm này làm nhiệm vụ load dữ liệu từ Scanner về Parser theo từng lượt ( dữ liệu load về trong một lượt gọi là chunk ) cho đến khi trên Scanner không còn dữ liệu Ngoài
ra, OnDataAvailable() còn có nhiệm vụ gọi đến hàm ResumeParse ( một hàm member của Parser ) để thực hiện việc phân tích cú pháp cho chunk dữ liệu vừa được load
Công việc đầu tiên của ResumeParse() là khởi động timer để đếm thời gian cho quá trình parsing, và lưu vào trong biến mParseTime của Parser Tiếp theo, gọi hàm WillBuildModel() của Parser, hàm này sẽ xác định ParseMode cho quá trình parsing
Không chỉ có mParseTime được lưu trữ trong Parser, thời gian thực hiện của quá trình tạo các token (tokenizing time), cũng được đếm và lưu trong biến mTokenizeTime của Parser Việc đếm thời gian tokenize được ContentSink thực hiện và theo dõi Trong Mozilla, quá trình parsing cũng như tokenizing được xác định nhờ vào các hàm mở đầu và kết thúc của quá trình Đối với parsing, hàm mở đầu là WillResumeParse() và hàm kết thúc là DidBuildModel() Đối với tokenizing, hàm mở đầu là WillTokenize() và hàm kết thúc quá trình là DidTokenize()
Trở lại quá trình thực hiện của ResumeParse() Sau khi hàm WillBuildModel() thực hiện xong, hàm Tokenize() sẽ được gọi để thực hiện quá trình tạo token Quá trình này thực sự do Tokenizer đảm nhận Do đó hàm Tokenize() của Parser phải gọi đến NavDTD, thông qua ParserContext, để yêu cầu khởi tạo một Tokenizer bằng cách gọi hàm GetTokenizer() trong đối tượng NavDTD Sau đó, Tokenizer được gọi để thực hiện hàm ConsumeToken()
ConsumeToken() là giai đoạn chủ yếu của quá trình parsing mà chúng ta cần tìm hiểu kỹ Như đã trình bày trước, một token được xem là một cụm từ trong source có cùng một chức năng xét trong văn phạm cú pháp HTML Vì vậy, dựa theo các chức năng của token mà lớp CTokens được phân ra nhiều lớp token con như phần trước ta đã biết
Công việc của hàm ConsumeToken trong đối tượng Tokenizer là xem qua một vài ký tự đầu của chuỗi dữ liệu nhận vào từ Scanner để xác định xem token
Trang 39đang xét thuộc loại token nào, và chọn lớp token thích hợp để gọi thực hiện hàm Consume() trong lớp token đó Hàm này sẽ tiếp tục công việc của ConsumeToken() là nhận tiếp dữ liệu từ Scanner cho đến khi token đó kết thúc Mỗi lớp token có một cách riêng để hàm Consume() nhận biết được đến đâu là ký tự cuối cùng của một token, nhờ vào đặc thù riêng về cú pháp của mỗi loại token
Cụ thể hơn, nội dung chi tiết của ConsumeToken() là thực hiện công việc sau :
Xác định xem nội dung của trang có đúng thuộc dạng HTML không Tiếp theo gọi hàm Peek() của Scanner để xem ký tự đầu tiên trong Scanner, sau đó xét các trường hợp sau tùy theo nội dung của ký tự này:
a) nếu đó là dấu < : gọi hàm member ConsumeTag() ( trong Tokenizer ) để thực hiện phần việc tiếp theo Đây là dấu hiệu bắt đầu một tag mới
b) nếu đó là dấu & : gọi hàm member ConsumeEntity() Ký tự này cho biết token sẽ là một entity trong HTML
c) nếu đó là dấu CarriageReturn hay LineFeed : gọi hàm ConsumeNewLine để xử lý vấn đề xuống dòng
d) nếu đó là khoảng trắng trong ASCII : gọi hàm Consume Whitespace() để xử lý các khoảng trắng
e) nếu đó là ký tự null : gọi hàm GetChar() ( trong Scanner ) để bỏ qua ký tự null
f) nếu đó là EOF : kết thúc
g) ngoài các trường hợp trên : gọi hàm ConsumeText() để đọc phần text vào token Đây đúng là đối tượng mà chúng ta cần phải chuyển mã nếu như trong token này có dùng mã tiếng Việt
Trang 40Như vậy, cách làm việc của hàm ConsumeToken() đã giúp chúng ta thấy rõ rằng đây là nơi mà chúng ta có thể đưa vào những phần code bổ sung nhằm thực hiện việc xét và chuyển mã cho những đoạn văn bản tiếng Việt ( nếu có )
Đến đây, chúng ta đã có thểâ xác định được rằng hàm Consume Token() trong lớp Tokenizer là nơi có thể chọn để bổ sung code vào Tuy nhiên, đối tượng Tokenizer không thể truy xuất trực tiếp đến nội dung của token, được định nghĩa qua biến mTextValue của từng lớp token cụ thể Do vậy chúng ta cần tìm hiểu thêm về hàm Consume() cụ thể đối với lớp nsTextToken, tức là hàm ConsumeText() thuộc đối tượng Tokenizer
Công việc của hàm này là gọi hàm GetTokenAllocator() để tạo ra một đối tượng thuộc lớp nsTokenAllocator Đối tượng này sẽ làm tiếp công việc là tạo một token thuộc lớp TextToken bằng cách gọi hàm CreateTokenOfType() Sau đó chính đối tượng TextToken này sẽ gọi hàm Consume() ( thuộc lớp nsTextToken ) để nhận về đầy đủ nội dung đoạn văn bản của token Trong hàm này, giá trị của biến mTextValue sẽ là nội dung đầy đủ của đoạn text Sau đó, token sẽ được đặt vào trong TokenDeque thông qua hàm AddToken ( của Tokenizer )
Như vậy, chúng ta có thể đưa đoạn code bổ sung _ để xét nội dung của token ( qua biến mTextValue ) và thực hiện việc chuyển đổi mã tiếng Việt _ vào trong hàm Consume() thuộc lớp TextToken
Ngoài ra, để những đoạn văn tiếng Việt sau khi được chuyển mã vẫn giữ đúng được phong thái như lúc ban đầu, thì ngoài việc chuyển mã chúng ta cần chuyển cả font chữ Việt của bảng mã cũ sang font chữ Việt tương ứng trong bảng mã mới
Việc xác định font chữ trong một trang HTML sẽ do thuộc tính family của thẻ <style> hoặc thuộc tính face trong thẻ <font> quyết định Nếu trong trang HTML có dùng font-family trong thẻ <style> để định dạng cho văn bản, thì nội dung của thuộc tính font này sẽ được đưa vào token qua hàm ConsumeUntil() của lớp TextToken Còn nếu trang HTML dùng thuộc tính face của thẻ <font> để định dạng thì nội dung của thuộc tính face sẽ được vào token bởi hàm Consume() của lớp AttributeToken