आधुनिक वेब ब्राउज़र के बारे में जानकारी
प्रस्तावना
WebKit और Gecko के इंटरनल ऑपरेशन के बारे में यह पूरी जानकारी, इज़रायल के डेवलपर ताली गार्सियल की रिसर्च का नतीजा है. कुछ सालों में, उन्होंने ब्राउज़र के इंटरनल के बारे में पब्लिश किए गए सभी डेटा की समीक्षा की. साथ ही, वेब ब्राउज़र के सोर्स कोड को पढ़ने में काफ़ी समय बिताया. उन्होंने लिखा:
वेब डेवलपर के तौर पर, ब्राउज़र के काम करने के तरीके के बारे में जानने से, आपको बेहतर फ़ैसले लेने में मदद मिलती है. साथ ही, डेवलपमेंट के सबसे सही तरीकों के पीछे की वजहों के बारे में भी पता चलता है. यह दस्तावेज़ काफ़ी लंबा है, लेकिन हमारा सुझाव है कि आप इसे ज़रूर पढ़ें. आपको बहुत खुशी होगी.
पॉल आयरिश, Chrome डेवलपर रिलेशनशिप
परिचय
वेब ब्राउज़र, सबसे ज़्यादा इस्तेमाल होने वाले सॉफ़्टवेयर हैं. इस प्राइमर में, मैंने बताया है कि ये सुविधाएं कैसे काम करती हैं. हम देखेंगे कि जब ब्राउज़र की स्क्रीन पर Google पेज दिखने तक, पता बार में google.com लिखा जाता है, तो क्या होता है.
हम इन ब्राउज़र के बारे में बात करेंगे
फ़िलहाल, डेस्कटॉप पर पांच मुख्य ब्राउज़र इस्तेमाल किए जाते हैं: Chrome, Internet Explorer, Firefox, Safari, और Opera. मोबाइल पर, मुख्य ब्राउज़र Android Browser, iPhone, Opera Mini और Opera Mobile, UC Browser, Nokia S40/S60 ब्राउज़र, और Chrome हैं. Opera ब्राउज़र को छोड़कर, ये सभी WebKit पर आधारित हैं. हम ओपन सोर्स ब्राउज़र Firefox और Chrome के साथ-साथ Safari (जो कुछ हद तक ओपन सोर्स है) के उदाहरण देंगे. StatCounter के आंकड़ों के मुताबिक (जून 2013 तक), दुनिया भर में डेस्कटॉप ब्राउज़र के इस्तेमाल में Chrome, Firefox, और Safari का योगदान करीब 71% है. मोबाइल पर, Android ब्राउज़र, iPhone, और Chrome का इस्तेमाल 54% तक होता है.
ब्राउज़र की मुख्य सुविधाएं
ब्राउज़र का मुख्य फ़ंक्शन, आपके चुने गए वेब संसाधन को दिखाना होता है. इसके लिए, वह सर्वर से अनुरोध करता है और उसे ब्राउज़र विंडो में दिखाता है. आम तौर पर, संसाधन एक एचटीएमएल दस्तावेज़ होता है. हालांकि, यह PDF, इमेज या किसी अन्य तरह का कॉन्टेंट भी हो सकता है. यूआरआई (यूनिफ़ॉर्म रिसॉर्स आइडेंटिफ़ायर) का इस्तेमाल करके, उपयोगकर्ता रिसॉर्स की जगह तय करता है.
एचटीएमएल और सीएसएस की खास बातों में बताया गया है कि ब्राउज़र, एचटीएमएल फ़ाइलों को कैसे समझता और दिखाता है. इन खास बातों को W3C (वर्ल्ड वाइड वेब कंसोर्टियम) संगठन मैनेज करता है. यह वेब के लिए स्टैंडर्ड तय करने वाला संगठन है. कई सालों तक ब्राउज़र, खास बातों के सिर्फ़ एक हिस्से का पालन करते थे और अपने एक्सटेंशन डेवलप करते थे. इससे वेब लेखकों को, अलग-अलग ब्राउज़र के साथ काम करने में गंभीर समस्याएं आ रही थीं. फ़िलहाल, ज़्यादातर ब्राउज़र इन खास बातों के मुताबिक काम करते हैं.
ब्राउज़र के यूज़र इंटरफ़ेस एक-दूसरे से काफ़ी मिलते-जुलते हैं. यूज़र इंटरफ़ेस के सामान्य एलिमेंट में ये शामिल हैं:
- यूआरआई डालने के लिए पता बार
- 'वापस जाएं' और 'आगे बढ़ें' बटन
- बुकमार्क करने के विकल्प
- मौजूदा दस्तावेज़ों को रीफ़्रेश करने या लोड होने से रोकने के लिए, रीफ़्रेश और रोकें बटन
- होम बटन, जो आपको होम पेज पर ले जाता है
हैरानी की बात यह है कि ब्राउज़र के यूज़र इंटरफ़ेस के बारे में किसी भी आधिकारिक स्पेसिफ़िकेशन में नहीं बताया गया है. यह सिर्फ़ सालों के अनुभव से बने अच्छे तरीकों और ब्राउज़र की एक-दूसरे की नकल करने से आता है. HTML5 स्पेसिफ़िकेशन में, ब्राउज़र में मौजूद होने वाले यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बारे में नहीं बताया गया है. हालांकि, इसमें कुछ सामान्य एलिमेंट की सूची दी गई है. इनमें पता बार, स्टेटस बार, और टूल बार शामिल हैं. हालांकि, कुछ सुविधाएं किसी खास ब्राउज़र के लिए खास होती हैं. जैसे, Firefox का डाउनलोड मैनेजर.
हाई-लेवल इन्फ़्रास्ट्रक्चर
ब्राउज़र के मुख्य कॉम्पोनेंट ये हैं:
- यूज़र इंटरफ़ेस: इसमें पता बार, पीछे/आगे जाने का बटन, बुकमार्क करने वाला मेन्यू वगैरह शामिल है. अनुरोध किया गया पेज दिखाने वाली विंडो को छोड़कर, ब्राउज़र के डिसप्ले का हर हिस्सा.
- ब्राउज़र इंजन: यह यूज़र इंटरफ़ेस (यूआई) और रेंडरिंग इंजन के बीच की कार्रवाइयों को मैर्शल करता है.
- रेंडरिंग इंजन: अनुरोध किया गया कॉन्टेंट दिखाने के लिए ज़िम्मेदार. उदाहरण के लिए, अगर अनुरोध किया गया कॉन्टेंट एचटीएमएल है, तो रेंडरिंग इंजन एचटीएमएल और सीएसएस को पार्स करता है और पार्स किए गए कॉन्टेंट को स्क्रीन पर दिखाता है.
- नेटवर्किंग: एचटीटीपी अनुरोधों जैसे नेटवर्क कॉल के लिए, प्लैटफ़ॉर्म पर काम करने वाले इंटरफ़ेस के पीछे, अलग-अलग प्लैटफ़ॉर्म के लिए अलग-अलग तरीके इस्तेमाल किए जाते हैं.
- यूज़र इंटरफ़ेस (यूआई) बैकएंड: इसका इस्तेमाल, कॉम्बो बॉक्स और विंडो जैसे बुनियादी विजेट बनाने के लिए किया जाता है. यह बैकएंड, एक सामान्य इंटरफ़ेस दिखाता है, जो किसी खास प्लैटफ़ॉर्म के लिए नहीं है. इसके तहत, ऑपरेटिंग सिस्टम के यूज़र इंटरफ़ेस के तरीकों का इस्तेमाल किया जाता है.
- JavaScript इंटरप्रिटर. इसका इस्तेमाल, JavaScript कोड को पार्स और लागू करने के लिए किया जाता है.
- डेटा स्टोरेज. यह पर्सिस्टेंस लेयर है. ब्राउज़र को स्थानीय रूप से सभी तरह का डेटा सेव करना पड़ सकता है, जैसे कि कुकी. ब्राउज़र, localStorage, IndexedDB, WebSQL, और फ़ाइल सिस्टम जैसे स्टोरेज मेकेनिज्म के साथ भी काम करते हैं.
यह ध्यान रखना ज़रूरी है कि Chrome जैसे ब्राउज़र, रेंडरिंग इंजन के कई इंस्टेंस चलाते हैं: हर टैब के लिए एक. हर टैब, एक अलग प्रोसेस में चलता है.
रेंडरिंग इंजन
रेंडरिंग इंजन की ज़िम्मेदारी है… रेंडरिंग करना. इसका मतलब है कि अनुरोध किए गए कॉन्टेंट को ब्राउज़र की स्क्रीन पर दिखाना.
रेंडरिंग इंजन, डिफ़ॉल्ट रूप से एचटीएमएल और एक्सएमएल दस्तावेज़ और इमेज दिखा सकता है. यह प्लग-इन या एक्सटेंशन की मदद से, अन्य तरह का डेटा दिखा सकता है. उदाहरण के लिए, PDF व्यूअर प्लग-इन का इस्तेमाल करके PDF दस्तावेज़ दिखाना. हालांकि, इस चैप्टर में हम मुख्य इस्तेमाल के उदाहरण पर फ़ोकस करेंगे: सीएसएस का इस्तेमाल करके फ़ॉर्मैट की गई एचटीएमएल और इमेज दिखाना.
अलग-अलग ब्राउज़र, अलग-अलग रेंडरिंग इंजन का इस्तेमाल करते हैं: Internet Explorer, Trident का इस्तेमाल करता है, Firefox, Gecko का इस्तेमाल करता है, और Safari, WebKit का इस्तेमाल करता है. Chrome और Opera (15 वर्शन से), WebKit के फ़ॉर्क Blink का इस्तेमाल करते हैं.
WebKit एक ओपन सोर्स रेंडरिंग इंजन है. इसे Linux प्लैटफ़ॉर्म के लिए इंजन के तौर पर शुरू किया गया था. Apple ने इसे Mac और Windows के साथ काम करने के लिए बदलाव किया था.
मुख्य फ़्लो
रेंडरिंग इंजन, अनुरोध किए गए दस्तावेज़ का कॉन्टेंट, नेटवर्किंग लेयर से पाने लगेगा. आम तौर पर, यह 8 केबी के हिस्सों में किया जाएगा.
इसके बाद, रेंडरिंग इंजन का बुनियादी फ़्लो यह है:
रेंडरिंग इंजन, एचटीएमएल दस्तावेज़ को पार्स करना शुरू कर देगा और एलिमेंट को "कॉन्टेंट ट्री" नाम के ट्री में डीओएम नोड में बदल देगा. इंजन, बाहरी सीएसएस फ़ाइलों और स्टाइल एलिमेंट, दोनों में स्टाइल डेटा को पार्स करेगा. एचटीएमएल में विज़ुअल निर्देशों के साथ स्टाइल की जानकारी का इस्तेमाल, एक और ट्री बनाने के लिए किया जाएगा: रेंडर ट्री.
रेंडर ट्री में, रंग और डाइमेंशन जैसे विज़ुअल एट्रिब्यूट वाले रेक्टैंगल होते हैं. स्क्रीन पर दिखाए जाने के लिए, रेक्टैंगल सही क्रम में हों.
रेंडर ट्री बनने के बाद, उसे "लेआउट" की प्रोसेस से गुज़रना पड़ता है. इसका मतलब है कि हर नोड को स्क्रीन पर दिखने की सटीक जगह के निर्देशांक देना. अगला चरण पेंटिंग है - रेंडर ट्री को ट्रैवर्स किया जाएगा और यूज़र इंटरफ़ेस (यूआई) बैकएंड लेयर का इस्तेमाल करके हर नोड को पेंट किया जाएगा.
यह समझना ज़रूरी है कि यह प्रोसेस धीरे-धीरे पूरी होती है. बेहतर उपयोगकर्ता अनुभव के लिए, रेंडरिंग इंजन, कॉन्टेंट को स्क्रीन पर जल्द से जल्द दिखाने की कोशिश करेगा. यह रेंडर ट्री बनाने और लेआउट करने से पहले, पूरे एचटीएमएल के पार्स होने का इंतज़ार नहीं करेगा. कॉन्टेंट के कुछ हिस्सों को पार्स करके दिखाया जाएगा. साथ ही, नेटवर्क से आने वाले बाकी कॉन्टेंट के लिए भी यह प्रोसेस जारी रहेगी.
मुख्य फ़्लो के उदाहरण
तीसरे और चौथे चित्र से पता चलता है कि WebKit और Gecko, थोड़ी अलग शब्दावली का इस्तेमाल करते हैं. हालांकि, फ़्लो एक जैसा ही है.
Gecko, विज़ुअल तौर पर फ़ॉर्मैट किए गए एलिमेंट के ट्री को "फ़्रेम ट्री" कहता है. हर एलिमेंट एक फ़्रेम होता है. WebKit, "रेंडर ट्री" शब्द का इस्तेमाल करता है. इसमें "रेंडर ऑब्जेक्ट" होते हैं. WebKit, एलिमेंट को प्लेस करने के लिए "लेआउट" शब्द का इस्तेमाल करता है, जबकि Gecko इसे "रीफ़्लो" कहता है. "अटैचमेंट", WebKit का वह शब्द है जिसका इस्तेमाल रेंडर ट्री बनाने के लिए, डीओएम नोड और विज़ुअल जानकारी को जोड़ने के लिए किया जाता है. एक छोटा सा गैर-समानार्थी अंतर यह है कि Gecko में एचटीएमएल और डीओएम ट्री के बीच एक अतिरिक्त लेयर होती है. इसे "कॉन्टेंट सिंक" कहा जाता है. यह डीओएम एलिमेंट बनाने वाली फ़ैक्ट्री है. हम फ़्लो के हर हिस्से के बारे में बात करेंगे:
पार्स करना - सामान्य जानकारी
पार्स करना, रेंडरिंग इंजन में एक बहुत अहम प्रोसेस है. इसलिए, हम इस बारे में थोड़ी ज़्यादा जानकारी देंगे. आइए, पार्स करने के बारे में थोड़ी जानकारी से शुरुआत करते हैं.
किसी दस्तावेज़ को पार्स करने का मतलब है, उसे ऐसे स्ट्रक्चर में बदलना जिसका इस्तेमाल कोड कर सके. आम तौर पर, पार्स करने का नतीजा नोड का एक ट्री होता है, जो दस्तावेज़ के स्ट्रक्चर को दिखाता है. इसे पार्स ट्री या सिंटैक्स ट्री कहा जाता है.
उदाहरण के लिए, एक्सप्रेशन 2 + 3 - 1 को पार्स करने पर, यह ट्री दिख सकता है:
व्याकरण
पार्सिंग, सिंटैक्स के उन नियमों पर आधारित होती है जिनका दस्तावेज़ पालन करता है: वह भाषा या फ़ॉर्मैट जिसमें उसे लिखा गया था. जिस भी फ़ॉर्मैट को पार्स किया जा सकता है उसमें व्याकरण का इस्तेमाल होना चाहिए. इसमें शब्दावली और सिंटैक्स के नियम शामिल होने चाहिए. इसे कॉन्टेक्स्ट फ़्री ग्रामर कहा जाता है. मानव भाषाएं ऐसी भाषाएं नहीं हैं. इसलिए, उन्हें पार्स करने के लिए, पार्स करने की पारंपरिक तकनीकों का इस्तेमाल नहीं किया जा सकता.
पार्सर - लेक्सर का कॉम्बिनेशन
पार्सिंग को दो उप-प्रोसेस में बांटा जा सकता है: लेक्सिकल विश्लेषण और सिंटैक्स विश्लेषण.
लेक्सिकल विश्लेषण, इनपुट को टोकन में बांटने की प्रोसेस है. टोकन, भाषा की शब्दावली होते हैं: मान्य बिल्डिंग ब्लॉक का कलेक्शन. सामान्य भाषा में, इसमें उस भाषा की डिक्शनरी में मौजूद सभी शब्द शामिल होंगे.
सिंटैक्स का विश्लेषण, भाषा के सिंटैक्स के नियमों को लागू करना है.
आम तौर पर, पार्स करने वाले टूल, काम को दो कॉम्पोनेंट में बांटते हैं: लेक्सर (इसे कभी-कभी टोकनेटर भी कहा जाता है), जो इनपुट को मान्य टोकन में बांटने के लिए ज़िम्मेदार होता है. दूसरा, पार्सर, जो भाषा के सिंटैक्स नियमों के हिसाब से दस्तावेज़ के स्ट्रक्चर का विश्लेषण करके, पार्स ट्री बनाता है.
लेक्सर, व्हाइट स्पेस और लाइन ब्रेक जैसे ग़ैर-ज़रूरी वर्णों को हटाने का तरीका जानता है.
पार्स करने की प्रोसेस बार-बार इस्तेमाल होती है. आम तौर पर, पार्स करने वाला टूल, लेक्सर से नया टोकन मांगेगा और टोकन को सिंटैक्स के किसी नियम से मैच करने की कोशिश करेगा. अगर कोई नियम मैच होता है, तो पार्स ट्री में टोक़न से जुड़ा एक नोड जोड़ दिया जाएगा. इसके बाद, पार्स करने वाला टूल किसी दूसरे टोक़न के लिए कहेगा.
अगर कोई नियम मेल नहीं खाता है, तो पार्स करने वाला टूल, टोक़न को अंदरूनी रूप से सेव करेगा. साथ ही, तब तक टोक़न मांगता रहेगा, जब तक अंदरूनी रूप से सेव किए गए सभी टोक़न से मेल खाने वाला कोई नियम नहीं मिल जाता. अगर कोई नियम नहीं मिलता है, तो पार्स करने वाला टूल एक अपवाद दिखाएगा. इसका मतलब है कि दस्तावेज़ अमान्य था और उसमें सिंटैक्स से जुड़ी गड़बड़ियां थीं.
अनुवाद
कई मामलों में, पार्स ट्री ही फ़ाइनल प्रॉडक्ट नहीं होता. पार्सिंग का इस्तेमाल, अक्सर अनुवाद में किया जाता है: इनपुट दस्तावेज़ को किसी दूसरे फ़ॉर्मैट में बदलना. इसका एक उदाहरण है, कलेक्शन. सोर्स कोड को मशीन कोड में कंपाइल करने वाला कंपाइलर, पहले उसे पार्स ट्री में पार्स करता है. इसके बाद, ट्री को मशीन कोड दस्तावेज़ में बदल देता है.
पार्स करने का उदाहरण
पांचवें चित्र में, हमने मैथमैटिकल एक्सप्रेशन से पार्स ट्री बनाया है. आइए, गणित की आसान भाषा को परिभाषित करने की कोशिश करते हैं और पार्स करने की प्रोसेस देखते हैं.
सिंटैक्स:
- भाषा के सिंटैक्स के बिल्डिंग ब्लॉक, एक्सप्रेशन, शब्द, और ऑपरेशन होते हैं.
- हमारी भाषा में जितने चाहें उतने एक्सप्रेशन शामिल किए जा सकते हैं.
- एक्सप्रेशन को "टर्म" के तौर पर परिभाषित किया जाता है. इसके बाद, "ऑपरेशन" और फिर एक और टर्म होता है
- ऑपरेशन, प्लस टोकन या माइनस टोकन होता है
- शब्द, इंटीजर टोकन या एक्सप्रेशन होता है
आइए, इनपुट 2 + 3 - 1 का विश्लेषण करते हैं.
किसी नियम से मैच करने वाली पहली सबस्ट्रिंग 2 है: नियम #5 के मुताबिक, यह एक शब्द है.
दूसरा मैच 2 + 3 है: यह तीसरे नियम से मेल खाता है: किसी शब्द के बाद कोई ऑपरेशन और उसके बाद कोई दूसरा शब्द.
अगला मैच सिर्फ़ इनपुट के आखिर में हिट होगा.
2 + 3 - 1 एक एक्सप्रेशन है, क्योंकि हम पहले से जानते हैं कि 2 + 3एक शब्द है. इसलिए, हमारे पास एक शब्द के बाद एक ऑपरेशन और उसके बाद एक और शब्द है.
2 + + किसी भी नियम से मैच नहीं करेगा. इसलिए, यह अमान्य इनपुट है.
शब्दावली और सिंटैक्स की औपचारिक परिभाषाएं
आम तौर पर, शब्दावली को रेगुलर एक्सप्रेशन से दिखाया जाता है.
उदाहरण के लिए, हमारी भाषा इस तरह से तय की जाएगी:
INTEGER: 0|[1-9][0-9]*
PLUS: +
MINUS: -
जैसा कि आप देख सकते हैं, पूर्णांकों को रेगुलर एक्सप्रेशन से तय किया जाता है.
सिंटैक्स को आम तौर पर BNF नाम के फ़ॉर्मैट में तय किया जाता है. हमारी भाषा को इस तरह से परिभाषित किया जाएगा:
expression := term operation term
operation := PLUS | MINUS
term := INTEGER | expression
हमने बताया था कि किसी भाषा को रेगुलर पार्सर से पार्स किया जा सकता है, बशर्ते उसका व्याकरण, कॉन्टेक्स्ट फ़्री ग्रामर हो. कॉन्टेक्स्ट फ़्री ग्रामर की आसान परिभाषा यह है कि यह एक ऐसा ग्रामर है जिसे पूरी तरह से बीएनएफ़ में दिखाया जा सकता है. इसकी औपचारिक परिभाषा के लिए, कॉन्टेक्स्ट-फ़्री ग्रामर के बारे में Wikipedia का लेख देखें
पार्सर के टाइप
पार्सर दो तरह के होते हैं: टॉप डाउन पार्सर और बॉटम अप पार्सर. आसान शब्दों में समझाने के लिए, यह कहा जा सकता है कि टॉप डाउन पार्सर, सिंटैक्स के हाई लेवल स्ट्रक्चर की जांच करते हैं और नियम से मैच होने वाले एलिमेंट ढूंढने की कोशिश करते हैं. बॉटम अप पार्सर, इनपुट से शुरू होते हैं और धीरे-धीरे इसे सिंटैक्स नियमों में बदल देते हैं. ये निचले लेवल के नियमों से शुरू होकर, उच्च लेवल के नियमों तक पहुंचते हैं.
आइए, देखें कि दो तरह के पार्स करने वाले टूल, हमारे उदाहरण को कैसे पार्स करेंगे.
टॉप-डाउन पार्सर, सबसे ऊपर के लेवल के नियम से शुरू होगा: यह 2 + 3 को एक्सप्रेशन के तौर पर पहचानेगा. इसके बाद, यह 2 + 3 - 1 को एक्सप्रेशन के तौर पर पहचानेगा. एक्सप्रेशन की पहचान करने की प्रोसेस, दूसरे नियमों से मैच करके आगे बढ़ती है. हालांकि, शुरुआती पॉइंट सबसे ऊंचे लेवल का नियम होता है.
बॉटम अप पार्सर, इनपुट को तब तक स्कैन करता रहेगा, जब तक किसी नियम से मेल नहीं खाता. इसके बाद, यह मेल खाने वाले इनपुट को नियम से बदल देगा. यह तब तक चलता रहेगा, जब तक इनपुट पूरा नहीं हो जाता. कुछ हद तक मैच होने वाला एक्सप्रेशन, पार्स करने वाले टूल के स्टैक पर रखा जाता है.
इस तरह के बॉटम अप पार्सर को शिफ़्ट-कम पार्सर कहा जाता है, क्योंकि इनपुट को दाईं ओर शिफ़्ट किया जाता है (एक पॉइंटर की कल्पना करें जो पहले इनपुट की शुरुआत पर होता है और दाईं ओर बढ़ता है). साथ ही, इसे सिंटैक्स नियमों में धीरे-धीरे कम किया जाता है.
पार्सर अपने-आप जनरेट होना
ऐसे टूल हैं जिनकी मदद से पार्सर जनरेट किया जा सकता है. आपको अपनी भाषा का व्याकरण - उसकी शब्दावली और सिंटैक्स के नियम - डालने होते हैं. इसके बाद, ये काम करने वाला पार्स करने वाला टूल जनरेट करते हैं. पार्सर बनाने के लिए, पार्सर के बारे में अच्छी तरह से जानना ज़रूरी है. साथ ही, मैन्युअल तरीके से ऑप्टिमाइज़ किया गया पार्सर बनाना आसान नहीं है. इसलिए, पार्सर जनरेटर का इस्तेमाल करना काफ़ी मददगार हो सकता है.
WebKit, दो जाने-माने पार्सर जनरेटर का इस्तेमाल करता है: लेक्सर बनाने के लिए Flex और पार्सर बनाने के लिए Bison. आपको ये Lex और Yacc के नाम से भी मिल सकते हैं. फ़्लेक्स इनपुट एक ऐसी फ़ाइल होती है जिसमें टोकन के रेगुलर एक्सप्रेशन की परिभाषाएं होती हैं. Bison का इनपुट, BNF फ़ॉर्मैट में भाषा के सिंटैक्स के नियम होते हैं.
एचटीएमएल पार्सर
एचटीएमएल पार्सर का काम, एचटीएमएल मार्कअप को पार्स ट्री में पार्स करना है.
एचटीएमएल व्याकरण
एचटीएमएल की शब्दावली और सिंटैक्स, W3C संगठन की बनाई गई खास बातों में बताया गया है.
जैसा कि हमने पार्सिंग के बारे में बताने वाले लेख में देखा है, व्याकरण के सिंटैक्स को BNF जैसे फ़ॉर्मैट का इस्तेमाल करके, औपचारिक तौर पर तय किया जा सकता है.
माफ़ करें, पार्सर के सभी सामान्य विषय एचटीएमएल पर लागू नहीं होते. मैंने इन्हें सिर्फ़ मनोरंजन के लिए नहीं बताया है - इनका इस्तेमाल सीएसएस और JavaScript को पार्स करने में किया जाएगा. एचटीएमएल को आसानी से उस कॉन्टेक्स्ट फ़्री ग्रामर से परिभाषित नहीं किया जा सकता जिसकी पार्स करने वालों को ज़रूरत होती है.
एचटीएमएल को तय करने के लिए एक फ़ॉर्मल फ़ॉर्मैट है - डीटीडी (दस्तावेज़ टाइप की परिभाषा) - लेकिन यह कॉन्टेक्स्ट फ़्री ग्रामर नहीं है.
पहली नज़र में यह अजीब लगता है, क्योंकि एचटीएमएल, एक्सएमएल से काफ़ी मिलता-जुलता है. एक्सएमएल पार्स करने वाले कई टूल उपलब्ध हैं. एचटीएमएल का एक एक्सएमएल वैरिएशन है - एक्सएचटीएमएल - तो इन दोनों में क्या फ़र्क़ है?
अंतर यह है कि एचटीएमएल का तरीका ज़्यादा "माफ़ करने वाला" है: इससे आपको कुछ टैग छोड़ने की अनुमति मिलती है (जिन्हें बाद में अपने-आप जोड़ दिया जाता है) या कभी-कभी शुरुआत या आखिर में मौजूद टैग छोड़ने की अनुमति मिलती है वगैरह. कुल मिलाकर, यह एक "सॉफ़्ट" सिंटैक्स है, जबकि एक्सएमएल का सिंटैक्स सख्त और ज़्यादा ज़रूरी है.
यह छोटी सी जानकारी काफ़ी मायने रखती है. एक तरफ़, एचटीएमएल इतना लोकप्रिय होने की मुख्य वजह यह है कि यह आपकी गलतियां माफ़ कर देता है और वेब लेखक के लिए काम को आसान बना देता है. दूसरी ओर, इससे फ़ॉर्मल व्याकरण लिखना मुश्किल हो जाता है. इसलिए, खास तौर पर यह बताना ज़रूरी है कि एचटीएमएल को पारंपरिक पार्स करने वाले टूल आसानी से पार्स नहीं कर सकते, क्योंकि इसका व्याकरण कॉन्टेक्स्ट फ़्री नहीं है. एक्सएमएल पार्सर, एचटीएमएल को पार्स नहीं कर सकते.
एचटीएमएल डीटीडी
एचटीएमएल डेफ़िनिशन, डीटीडी फ़ॉर्मैट में हो. इस फ़ॉर्मैट का इस्तेमाल, SGML फ़ैमिली की भाषाओं को तय करने के लिए किया जाता है. इस फ़ॉर्मैट में, इस्तेमाल किए जा सकने वाले सभी एलिमेंट, उनके एट्रिब्यूट, और हैरारकी की परिभाषाएं शामिल होती हैं. जैसा कि हमने पहले देखा था, एचटीएमएल डीटीडी, कॉन्टेक्स्ट-फ़्री ग्रामर नहीं बनाता.
डीटीडी के कुछ वैरिएंट हैं. स्ट्रिक्ट मोड, सिर्फ़ खास बातों के मुताबिक काम करता है. हालांकि, दूसरे मोड में ब्राउज़र के पहले इस्तेमाल किए गए मार्कअप के लिए सहायता होती है. इसका मकसद, पुराने वीडियो के साथ काम करना है. सख्त DTD का मौजूदा वर्शन यहां दिया गया है: www.w3.org/TR/html4/strict.dtd
डीओएम
आउटपुट ट्री ("पार्स ट्री"), डीओएम एलिमेंट और एट्रिब्यूट नोड का ट्री होता है. डीओएम, डॉक्यूमेंट ऑब्जेक्ट मॉडल का छोटा नाम है. यह एचटीएमएल दस्तावेज़ का ऑब्जेक्ट प्रज़ेंटेशन और JavaScript जैसे बाहरी दुनिया के लिए एचटीएमएल एलिमेंट का इंटरफ़ेस है.
ट्री का रूट, "दस्तावेज़" ऑब्जेक्ट होता है.
डीओएम का मार्कअप से एक-एक का संबंध होता है. उदाहरण के लिए:
<html>
<body>
<p>
Hello World
</p>
<div> <img src="example.png"/></div>
</body>
</html>
इस मार्कअप को इस डीओएम ट्री में बदल दिया जाएगा:
एचटीएमएल की तरह, डीओएम को भी W3C संगठन तय करता है. www.w3.org/DOM/DOMTR देखें. यह दस्तावेज़ों में बदलाव करने के लिए सामान्य तौर पर इस्तेमाल होने वाली जानकारी है. किसी खास मॉड्यूल में, एचटीएमएल के खास एलिमेंट के बारे में बताया जाता है. एचटीएमएल की परिभाषाएं यहां देखी जा सकती हैं: www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html.
जब हम कहते हैं कि ट्री में डीओएम नोड होते हैं, तो हमारा मतलब है कि ट्री को ऐसे एलिमेंट से बनाया जाता है जो डीओएम इंटरफ़ेस में से किसी एक को लागू करते हैं. ब्राउज़र, ऐसे लागू किए गए एट्रिब्यूट का इस्तेमाल करते हैं जिनमें ब्राउज़र के अंदर इस्तेमाल किए जाने वाले अन्य एट्रिब्यूट होते हैं.
पार्स करने का एल्गोरिदम
जैसा कि हमने पिछले सेक्शन में देखा था, एचटीएमएल को टॉप डाउन या बॉटम अप पार्सर का इस्तेमाल करके पार्स नहीं किया जा सकता.
इसकी वजहें ये हैं:
- भाषा में गड़बड़ियों को माफ़ करने की सुविधा.
- ब्राउज़र में गड़बड़ी को सहन करने की सुविधा होती है, ताकि अमान्य एचटीएमएल के आम तौर पर होने वाले मामलों को ठीक किया जा सके.
- पार्स करने की प्रोसेस को फिर से शुरू किया जा सकता है. दूसरी भाषाओं के लिए, पार्स करने के दौरान सोर्स में कोई बदलाव नहीं होता. हालांकि, एचटीएमएल में डाइनैमिक कोड (जैसे,
document.write()कॉल वाले स्क्रिप्ट एलिमेंट) अतिरिक्त टोकन जोड़ सकते हैं. इसलिए, पार्स करने की प्रोसेस में, इनपुट में बदलाव होता है.
सामान्य पार्सिंग तकनीकों का इस्तेमाल न कर पाने की वजह से, ब्राउज़र एचटीएमएल को पार्स करने के लिए कस्टम पार्सर बनाते हैं.
पार्सिंग एल्गोरिदम के बारे में ज़्यादा जानकारी, HTML5 स्पेसिफ़िकेशन में दी गई है. एल्गोरिदम में दो चरण होते हैं: टोकनाइज़ेशन और ट्री का निर्माण.
टोकनाइज़ेशन, लेक्सिकल विश्लेषण है. इसमें इनपुट को टोकन में पार्स किया जाता है. एचटीएमएल टोकन में, स्टार्ट टैग, एंड टैग, एट्रिब्यूट के नाम, और एट्रिब्यूट की वैल्यू शामिल हैं.
टोकेनर, टोकन की पहचान करता है और उसे ट्री कन्स्ट्रक्टर को देता है. साथ ही, अगले टोकन की पहचान करने के लिए अगले वर्ण का इस्तेमाल करता है. यह प्रक्रिया, इनपुट के आखिर तक चलती रहती है.
टोकनाइज़ेशन एल्गोरिदम
एल्गोरिदम का आउटपुट एक एचटीएमएल टोकन होता है. एल्गोरिदम को स्टेट मशीन के तौर पर दिखाया जाता है. हर स्टेटस, इनपुट स्ट्रीम के एक या उससे ज़्यादा वर्णों का इस्तेमाल करता है और उन वर्णों के हिसाब से अगला स्टेटस अपडेट करता है. यह फ़ैसला, टोकनाइज़ेशन की मौजूदा स्थिति और ट्री बनाने की स्थिति से तय होता है. इसका मतलब है कि मौजूदा स्थिति के आधार पर, इस्तेमाल किए गए एक ही वर्ण से अगली सही स्थिति के लिए अलग-अलग नतीजे मिलेंगे. एल्गोरिदम को पूरी तरह से समझाना बहुत मुश्किल है. इसलिए, एक आसान उदाहरण देखें, जिससे हमें सिद्धांत को समझने में मदद मिलेगी.
बुनियादी उदाहरण - इस एचटीएमएल को टोकन में बदलना:
<html>
<body>
Hello world
</body>
</html>
शुरुआती स्थिति, "डेटा स्टेटस" होती है.
< वर्ण मिलने पर, स्टेटस को "टैग खुला है" में बदल दिया जाता है.
a-z वर्ण का इस्तेमाल करने पर, "स्टार्ट टैग टोकन" बन जाता है. साथ ही, स्टेटस "टैग के नाम की स्थिति" में बदल जाता है.
हम इस स्थिति में तब तक बने रहते हैं, जब तक > वर्ण का इस्तेमाल नहीं हो जाता. हर वर्ण, नए टोकन के नाम में जोड़ दिया जाता है. हमारे मामले में, बनाया गया टोकन एक html टोकन है.
> टैग तक पहुंचने पर, मौजूदा टोकन उत्सर्जित किया जाता है और स्टेटस वापस "डेटा स्टेटस" में बदल जाता है.
<body> टैग को भी इसी तरह से प्रोसेस किया जाएगा.
अब तक html और body टैग उत्सर्जित किए गए थे. अब हम "डेटा की स्थिति" पर वापस आ गए हैं.
Hello world के H वर्ण का इस्तेमाल करने पर, एक वर्ण टोकन बनेगा और उसे भेजा जाएगा. ऐसा तब तक होता रहेगा, जब तक </body> के < तक नहीं पहुंचा जाता. हम Hello world के हर वर्ण के लिए एक वर्ण टोकन उत्सर्जित करेंगे.
अब हम "टैग के खुले होने की स्थिति" पर वापस आ गए हैं.
अगले इनपुट / का इस्तेमाल करने पर, एक end tag token बन जाएगा और "टैग के नाम की स्थिति" पर ले जाया जाएगा. हम फिर से इस स्थिति में तब तक बने रहते हैं, जब तक कि हम > तक नहीं पहुंच जाते.इसके बाद, नया टैग टोकन उत्सर्जित किया जाएगा और हम "डेटा स्टेटस" पर वापस चले जाएंगे.
</html> इनपुट को पिछले मामले की तरह ही माना जाएगा.
ट्री स्ट्रक्चर बनाने का एल्गोरिदम
पार्स करने वाला टूल बनाने पर, दस्तावेज़ ऑब्जेक्ट बन जाता है. ट्री बनाने के दौरान, रूट में दस्तावेज़ वाले डीओएम ट्री में बदलाव किया जाएगा और उसमें एलिमेंट जोड़े जाएंगे. tokenizer से उत्सर्जित हर नोड को ट्री कन्स्ट्रक्टर प्रोसेस करेगा. हर टोकन के लिए, स्पेसिफ़िकेशन से यह तय होता है कि कौनसा DOM एलिमेंट उसके लिए काम का है और इस टोकन के लिए बनाया जाएगा. एलिमेंट को DOM ट्री में जोड़ा जाता है. साथ ही, ओपन एलिमेंट के स्टैक में भी जोड़ा जाता है. इस स्टैक का इस्तेमाल, नेस्टिंग मैच न होने और बंद नहीं किए गए टैग को ठीक करने के लिए किया जाता है. एल्गोरिदम को स्टेट मशीन भी कहा जाता है. इन स्थितियों को "शामिल करने के मोड" कहा जाता है.
आइए, उदाहरण के तौर पर दिए गए इनपुट के लिए, ट्री स्ट्रक्चर बनाने की प्रोसेस देखें:
<html>
<body>
Hello world
</body>
</html>
ट्री बनाने के चरण में, टोकन बनाने के चरण से मिले टोकन का क्रम इनपुट के तौर पर इस्तेमाल किया जाता है. पहला मोड, "शुरुआती मोड" है. "html" टोकन मिलने पर, "html से पहले" मोड पर स्विच हो जाएगा और उस मोड में टोकन को फिर से प्रोसेस किया जाएगा. इससे HTMLHtmlElement एलिमेंट बन जाएगा, जिसे रूट दस्तावेज़ ऑब्जेक्ट में जोड़ दिया जाएगा.
स्टेटस बदलकर "before head" हो जाएगा. इसके बाद, "body" टोकन मिलता है. हमारे पास "head" टोकन न होने पर भी, HTMLHeadElement अपने-आप बन जाएगा और उसे ट्री में जोड़ दिया जाएगा.
अब हम "सिर के अंदर" मोड पर जाते हैं और फिर "सिर के बाद" मोड पर जाते हैं. बॉडी टोकन को फिर से प्रोसेस किया जाता है, एक HTMLBodyElement बनाया और डाला जाता है. साथ ही, मोड को "बॉडी में" पर ट्रांसफ़र किया जाता है.
"Hello world" स्ट्रिंग के वर्ण टोकन अब मिल गए हैं. पहले विकल्प की मदद से, "टेक्स्ट" नोड बनाया और डाला जाएगा. साथ ही, दूसरे वर्ण उस नोड में जोड़ दिए जाएंगे.
बॉडी एंड टोकन मिलने पर, "बॉडी के बाद" मोड पर ट्रांसफ़र हो जाएगा. अब हमें एचटीएमएल का आखिरी टैग मिलेगा, जो हमें "body के बाद" मोड पर ले जाएगा. फ़ाइल के आखिर में मौजूद टोकन मिलने पर, पार्सिंग की प्रोसेस खत्म हो जाएगी.
पार्स करने के बाद की जाने वाली कार्रवाइयां
इस चरण में, ब्राउज़र दस्तावेज़ को इंटरैक्टिव के तौर पर मार्क करेगा और "देर से" मोड में मौजूद स्क्रिप्ट को पार्स करना शुरू कर देगा. ये ऐसी स्क्रिप्ट होती हैं जिन्हें दस्तावेज़ को पार्स करने के बाद ही लागू किया जाना चाहिए. इसके बाद, दस्तावेज़ की स्थिति "पूरा हुआ" पर सेट हो जाएगी और "लोड" इवेंट ट्रिगर हो जाएगा.
HTML5 स्पेसिफ़िकेशन में, टोकन बनाने और ट्री बनाने के लिए पूरे एल्गोरिदम देखे जा सकते हैं.
ब्राउज़र में गड़बड़ी की सीमा
आपको एचटीएमएल पेज पर कभी भी "अमान्य सिंटैक्स" गड़बड़ी नहीं दिखती. ब्राउज़र, अमान्य कॉन्टेंट को ठीक कर देते हैं और आगे बढ़ जाते हैं.
उदाहरण के लिए, यह एचटीएमएल:
<html>
<mytag>
</mytag>
<div>
<p>
</div>
Really lousy HTML
</p>
</html>
मैंने करीब एक लाख नियमों का उल्लंघन किया है ("mytag" स्टैंडर्ड टैग नहीं है, "p" और "div" एलिमेंट का गलत नेस्टिंग वगैरह), लेकिन ब्राउज़र अब भी इसे सही तरीके से दिखाता है और कोई शिकायत नहीं करता. इसलिए, पार्सर कोड का ज़्यादातर हिस्सा, एचटीएमएल लेखक की गलतियां ठीक कर रहा है.
ब्राउज़र में गड़बड़ी को मैनेज करने का तरीका काफ़ी हद तक एक जैसा होता है. हालांकि, हैरानी की बात है कि यह एचटीएमएल के स्पेसिफ़िकेशन का हिस्सा नहीं है. यह सुविधा, ब्राउज़र में पिछले कुछ सालों में विकसित हुई है. यह सुविधा, बुकमार्क करने और पीछे/आगे जाने के बटन की तरह ही है. कई साइटों पर, अमान्य एचटीएमएल कॉन्स्ट्रक्ट बार-बार इस्तेमाल किए जाते हैं. ब्राउज़र, उन्हें दूसरे ब्राउज़र के मुताबिक ठीक करने की कोशिश करते हैं.
HTML5 स्पेसिफ़िकेशन में इनमें से कुछ ज़रूरी शर्तों के बारे में बताया गया है. (WebKit, एचटीएमएल पार्स करने वाली क्लास की शुरुआत में मौजूद टिप्पणी में इस बारे में अच्छी तरह से बताता है.)
पार्सर, दस्तावेज़ में टोकन किए गए इनपुट को पार्स करता है और दस्तावेज़ ट्री बनाता है. अगर दस्तावेज़ सही तरीके से बनाया गया है, तो उसे पार्स करना आसान होता है.
माफ़ करें, हमें ऐसे कई एचटीएमएल दस्तावेज़ हैं जो सही तरीके से नहीं बनाए गए हैं. इसलिए, पार्स करने वाले टूल को गड़बड़ियों को स्वीकार करना होगा.
हमें गड़बड़ी की कम से कम इन स्थितियों का ध्यान रखना होगा:
- जो एलिमेंट जोड़ा जा रहा है उसे किसी बाहरी टैग के अंदर इस्तेमाल करने की अनुमति नहीं है. इस मामले में, हमें उस टैग तक सभी टैग बंद कर देने चाहिए जो एलिमेंट को अनुमति नहीं देता. इसके बाद, उस टैग को जोड़ें.
- हमारे पास एलिमेंट को सीधे जोड़ने की अनुमति नहीं है. ऐसा हो सकता है कि दस्तावेज़ लिखने वाले व्यक्ति ने बीच में कोई टैग इस्तेमाल करना न भूल हो या बीच में इस्तेमाल किया जाने वाला टैग ज़रूरी न हो. यह इन टैग के साथ हो सकता है: एचटीएमएल हेड बॉडी टीबीडी टीआर टीडी एलआई (क्या मैंने कोई टैग छूटा है?).
- हमें इनलाइन एलिमेंट में ब्लॉक एलिमेंट जोड़ना है. अगले ब्लॉक एलिमेंट तक सभी इनलाइन एलिमेंट बंद करें.
- अगर इससे मदद नहीं मिलती है, तो तब तक एलिमेंट बंद रखें, जब तक हमें एलिमेंट जोड़ने की अनुमति नहीं मिल जाती. इसके अलावा, टैग को अनदेखा भी किया जा सकता है.
आइए, WebKit के गड़बड़ी को सहन करने की सुविधा के कुछ उदाहरण देखें:
<br> के बजाय </br>
कुछ साइटें <br> के बजाय </br> का इस्तेमाल करती हैं. IE और Firefox के साथ काम करने के लिए, WebKit इसे <br> की तरह इस्तेमाल करता है.
कोड:
if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
reportError(MalformedBRError);
t->beginTag = true;
}
ध्यान दें कि गड़बड़ी को मैनेज करने की प्रोसेस इंटरनल है: यह उपयोगकर्ता को नहीं दिखाई जाएगी.
कोई ऐसी टेबल जो किसी कैटगरी में नहीं है
अलग-थलग टेबल, किसी टेबल सेल के बजाय किसी दूसरी टेबल में मौजूद टेबल होती है.
उदाहरण के लिए:
<table>
<table>
<tr><td>inner table</td></tr>
</table>
<tr><td>outer table</td></tr>
</table>
WebKit, हैरारकी को दो सिबलिंग टेबल में बदल देगा:
<table>
<tr><td>outer table</td></tr>
</table>
<table>
<tr><td>inner table</td></tr>
</table>
कोड:
if (m_inStrayTableContent && localName == tableTag)
popBlock(tableTag);
WebKit, मौजूदा एलिमेंट के कॉन्टेंट के लिए स्टैक का इस्तेमाल करता है: यह आंतरिक टेबल को बाहरी टेबल स्टैक से बाहर पॉप कर देगा. अब ये टेबल, एक-दूसरे से जुड़ी होंगी.
नेस्ट किए गए फ़ॉर्म एलिमेंट
अगर उपयोगकर्ता किसी फ़ॉर्म में कोई दूसरा फ़ॉर्म डालता है, तो दूसरे फ़ॉर्म को अनदेखा कर दिया जाता है.
कोड:
if (!m_currentFormElement) {
m_currentFormElement = new HTMLFormElement(formTag, m_document);
}
टैग की हैरारकी बहुत गहरी है
टिप्पणी से ही साफ़ तौर पर पता चलता है कि दर्शक इस बारे में क्या सोचते हैं.
bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{
unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}
एचटीएमएल या मुख्य हिस्से के आखिर में मौजूद टैग गलत जगह पर हैं
फिर से - टिप्पणी से ही साफ़ तौर पर पता चलता है कि दर्शक किस तरह की कॉन्टेंट पसंद करते हैं.
if (t->tagName == htmlTag || t->tagName == bodyTag )
return;
इसलिए, वेब लेखकों को सावधान रहना चाहिए. अगर आपको WebKit के गड़बड़ी को सहन करने वाले कोड स्निपेट में उदाहरण के तौर पर नहीं दिखना है, तो सही तरीके से एचटीएमएल लिखें.
सीएसएस पार्सिंग
क्या आपको शुरुआत में दिए गए पार्सिंग के कॉन्सेप्ट याद हैं? एचटीएमएल के उलट, सीएसएस एक कॉन्टेक्स्ट-फ़्री ग्रामर है. इसे शुरुआत में बताए गए पार्सर का इस्तेमाल करके पार्स किया जा सकता है. असल में, सीएसएस स्पेसिफ़िकेशन में सीएसएस लेक्सिकल और सिंटैक्स ग्रामर के बारे में बताया गया है.
आइए, कुछ उदाहरण देखते हैं:
हर टोकन के लिए, रेगुलर एक्सप्रेशन से लेक्सिकल ग्रामर (शब्दावली) तय की जाती है:
comment \/\*[^*]*\*+([^/*][^*]*\*+)*\/
num [0-9]+|[0-9]*"."[0-9]+
nonascii [\200-\377]
nmstart [_a-z]|{nonascii}|{escape}
nmchar [_a-z0-9-]|{nonascii}|{escape}
name {nmchar}+
ident {nmstart}{nmchar}*
"ident", आइडेंटिफ़ायर का छोटा रूप है, जैसे कि क्लास का नाम. "name" एक एलिमेंट आईडी है, जिसे "#" से रेफ़र किया जाता है
सिंटैक्स ग्रामर के बारे में BNF में बताया गया है.
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;
selector
: simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
;
simple_selector
: element_name [ HASH | class | attrib | pseudo ]*
| [ HASH | class | attrib | pseudo ]+
;
class
: '.' IDENT
;
element_name
: IDENT | '*'
;
attrib
: '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
[ IDENT | STRING ] S* ] ']'
;
pseudo
: ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
;
व्याख्या:
नियमों का सेट इस स्ट्रक्चर में होता है:
div.error, a.error {
color:red;
font-weight:bold;
}
div.error और a.error सिलेक्टर हैं. कर्ली ब्रैकेट के अंदर मौजूद हिस्से में वे नियम होते हैं जो इस नियमों के सेट के हिसाब से लागू होते हैं.
इस स्ट्रक्चर की जानकारी, इस परिभाषा में दी गई है:
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;
इसका मतलब है कि नियमों का सेट एक सिलेक्टर है या वैकल्पिक रूप से, कॉमा और स्पेस से अलग किए गए कई सिलेक्टर हैं. S का मतलब खाली जगह है. नियमों के सेट में कर्ली ब्रैकेट होते हैं. इनमें एक एलान या कई एलान होते हैं. ये एलान, सेमीकोलन से अलग किए जाते हैं. "एलान" और "सिलेक्टर" की परिभाषा, नीचे दी गई बीएनएफ़ परिभाषाओं में दी गई है.
WebKit CSS पार्स करने वाला टूल
WebKit, CSS व्याकरण फ़ाइलों से अपने-आप पार्स करने वाले टूल बनाने के लिए, Flex और Bison पार्सर जनरेटर का इस्तेमाल करता है. जैसा कि आपको पार्स करने वाले टूल के बारे में जानकारी देने वाले लेख में बताया गया था, Bison एक बॉटम अप शिफ़्ट-रीड्यूस पार्स करने वाला टूल बनाता है. Firefox, मैन्युअल तरीके से लिखे गए टॉप डाउन पार्सर का इस्तेमाल करता है. दोनों ही मामलों में, हर CSS फ़ाइल को स्टाइलशीट ऑब्जेक्ट में पार्स किया जाता है. हर ऑब्जेक्ट में सीएसएस नियम होते हैं. सीएसएस नियम ऑब्जेक्ट में, सिलेक्टर और डिक्लेरेशन ऑब्जेक्ट के साथ-साथ सीएसएस व्याकरण से जुड़े अन्य ऑब्जेक्ट शामिल होते हैं.
स्क्रिप्ट और स्टाइल शीट के लिए प्रोसेसिंग का क्रम
स्क्रिप्ट
वेब का मॉडल सिंक्रोनस है. लेखकों को उम्मीद होती है कि पार्स करने वाला टूल, <script> टैग पर पहुंचते ही स्क्रिप्ट को पार्स करके तुरंत लागू कर देगा.
स्क्रिप्ट लागू होने तक, दस्तावेज़ को पार्स करने की प्रोसेस रुक जाती है.
अगर स्क्रिप्ट बाहरी है, तो संसाधन को पहले नेटवर्क से फ़ेच करना होगा - यह भी सिंक्रोनस तरीके से किया जाता है. साथ ही, संसाधन फ़ेच होने तक पार्सिंग रुक जाती है.
यह कई सालों तक मॉडल था और इसे HTML4 और 5 के स्पेसिफ़िकेशन में भी बताया गया है.
लेखक, स्क्रिप्ट में "defer" एट्रिब्यूट जोड़ सकते हैं. ऐसा करने पर, दस्तावेज़ को पार्स करने की प्रोसेस रुक नहींेगी और स्क्रिप्ट, दस्तावेज़ को पार्स करने के बाद ही चलेगी. HTML5 में, स्क्रिप्ट को असाइनोक्रोनस के तौर पर मार्क करने का विकल्प जोड़ा गया है, ताकि उसे कि