使用 microformats 分離數據與格式

發表于:2007-05-24來源:作者:點擊數: 標簽:microformats分離格式使用數據
微格式(Microformat)是在標準 XHTML 代碼中嵌入結構化數據的一種新方法。閱讀本文,了解如何讀寫 Web 這種全新的微格式。 每當我偶爾看到有人靈光一閃產生的某個理念,我就會自言自語:我要是能想到這個該多好,真是天才! 微格式正是這樣一種理念。您知道
微格式(Microformat)是在標準 XHTML 代碼中嵌入結構化數據的一種新方法。閱讀本文,了解如何讀寫 Web 這種全新的微格式。

每當我偶爾看到有人靈光一閃產生的某個理念,我就會自言自語:“我要是能想到這個該多好,真是天才!” 微格式正是這樣一種理念。您知道,人們一直在嘗試從非結構化的 Web 中提取結構化數據。在人們討論 “語義 Web”(數據與格式分離的一種 Web)時,您會聽到一些與此相關的內容。而無論如何,語義 Web 尚未消失,所有在非結構化世界中尋找結構化數據的問題依然存在。

迄今為止,微格式是向著導出 Web 上的結構化數據這一方向邁進的一小步。理念非常簡單。獲得一個包含某些事件信息的頁面:開始時間、結束時間、位置、主題、Web 頁面,等等。過去的方法是將這些信息放置在頁面的超文本標記語言(HTML)中,微格式摒棄了這種做法,而是添加一些標準化 HTML 標記和層疊樣式表(CSS)類名。頁面依然可以保留您選擇的任何外觀,但對于尋找這些格式化的(或者應該說,是微格式化的)HTML 片段的瀏覽器來說,變化無處不在。

或許查看一段微格式化的 HTML 能幫助您理解這種概念。清單 1 展示了格式化為 hCalendar 微格式標準的一個事件。


清單 1. 一個簡單的事件頁面
<html>
            <body>
            <div class="vevent">
            <a class="url" href="http://myevent.com">
            <abbr class="dtstart" title="20060501">May 1</abbr> -
            <abbr class="dtend" title="20060502">02, 2006</abbr>
            <span class="summary">My Conference opening</span> - at
            <span class="location">Hollywood, CA</span>
            </a>
            <div class="description">The opening days of the conference</div>
            </div>
            </body>
            </html>
            

單獨的一個頁面上可以有多個事件,各事件均包含于一個用 vevent 類進行標記的 <div> 標記中。在這個 <div> 標記中是使用不同的標記進行標記的事件數據,有些人用特定的類來標記事件數據。url 類是轉向 Web 頁面的定位點。dtstartdtend 類位于 title 元素中編碼了開始時間和結束時間的標記內。summary、locationdescription 類均屬于包含相應內容的標記。

現在,這些條目所在的頁面即可使用 CSS 任選方式來編碼這些條目了。因此,卡片的外觀對于站點來說依然是惟一的。類的命名規范才是最重要的。

這就是微格式要處理的全部。微格式的 Web 站點就像是一個維基百科,您可為想展示的任何數據添加您自己的格式。在我上一次查看該站點時,那里有用于事件、聯系信息、評論及其他許多方面的格式。站點中甚至還提供了一個方便的格式創建程序,如 圖 1 所示。


圖 1. hCalendar 創建程序頁面
hCalendar 創建程序頁面

在這篇文章中,我使用 PHP 將給定頁面中的事件記錄提取為 XML 格式。然后創建另外一個 PHP 頁面來接受這種 XML,并通過以 hCalendar 微格式編碼的事件構建一個 HTML 頁面。在此之前,先簡要介紹一下微格式的優點和缺點。

優點和缺點

坦白地說,任何經驗豐富的工程師在看過上面的 hCalendar 示例后都會問 “這種微格式 中的格式在哪里?” 的確,微格式算不上一種獨立的格式,倒不如說是已有格式(HTML)之上的一層。不得不承認,這是微格式的缺點之一。觀察以下對比代碼,您會更清楚地理解我的意思:

BEGIN:vCalendar
            VERSION:5.0
            PRODID:-//Microsoft Corporation//Works 2000//EN
            BEGIN:vEvent
            DTSTART: 20060501T000000
            DTEND: 20060502T000000
            SUMMARY;ENCODING=QUOTED-PRINTABLE: My Conference opening
            PRIORITY: 3
            END:vEvent
            END:vCalendar
            

這段代碼強大、易于閱讀,毫無疑問,它也非常容易解析。這段代碼看上去似乎超出了 Fortran 77 或早期的 UNIX® 慣例。您可以毫不困難地設想出一種 XML 替代格式,能夠對上述格式略加改進。但要想從中獲取這種信息格式,您必須編寫專用的客戶機。這是新標準乃至 XML 標準的一個很大的缺點,卻是微格式的顯著優點。

使用微格式,您能利用兩種極為成功的技術:HTTP(Hypertext Transfer Protocol)和 HTML。這兩種標準集成到了世界上的所有桌面中,工程師們一直在努力拓展其用途,使您能夠利用它們做更多的事情。

以 Greasemonkey 為例。Greasemonkey 是 Mozilla Firefox 瀏覽器的一個絕妙擴展,允許您在載入一個頁面之后為頁面應用 JavaScript 代碼。有些人使用此擴展來移除標題廣告。有些人用它在不受自己控制的站點上添加額外的信息。另外還有些人編寫 Greasemonkey 腳本來查找微格式化的數據。最妙的就是腳本是用 JavaScript 代碼編寫的,因此您不必擔心平臺問題。這里完全不需要 Win32 或 Cocoa:只要使用可移植 JavaScript 代碼編寫您的擴展即可。但對于非 HTML 頁面,Greasemonkey 是不起作用的,此時就是微格式大顯身手的時機了。

在介紹微格式時,我想采用先抑后揚的方法,我將回顧不久前我在華盛頓西雅圖的一次技術研討會上的經歷。當時我在與 Technorati(一個博客搜索引擎)的創建者之一交談,我認為繼 HTML 之后,最成功的基于標記的數據格式應該是 RSS。但在談話中,那個人指出大多數 RSS 要么形式不佳,要么比較過時,所以 Technorati 不依靠 RSS。他們直接使用 HTML,并在代碼中尋求博客風格的模式。

這并不表示 RSS 不好:我熱愛 RSS。但我認為在現實中使人們接受 HTML 以外的其他格式非常艱難。所以在 HTML 之上設置格式更有意義。

現在,停止我的長篇大論,讓我們來看看代碼。先來讀取一個頁面中的微格式。





回頁首


讀取微格式

要讀取一個使用微格式數據編碼的頁面,您必須獲得一個其上具有事件的 Web 頁面。我從一個 .html 文件入手,如 清單 2 所示。


清單 2. Hcalendar.html
<html>
            <head>
            <style>
            body { font-family: arial, verdana, sans-serif; }
            </style>
            </head>
            <body>
            <div style="width:600px;">
            <div class="vevent" id="one">
            <a class="url" href="http://myevent.com">
            <abbr class="dtstart" title="20060501">May 1</abbr> -
            <abbr class="dtend" title="20060502">02, 2006</abbr>
            <span class="summary">My Conference opening</span> - at
            <span class="location">Hollywood, CA</span>
            </a>
            <div class="description">The opening days of the conference</div>
            </div>
            <div class="vevent" id="two">
            <a class="url" href="http://myevent.com">
            <abbr class="dtstart" title="20060503">May 3</abbr> -
            <abbr class="dtend" title="20060504">04, 2006</abbr>
            <span class="summary">My Conference closing</span> - at
            <span class="location">Hollywood, CA</span>
            </a>
            <div class="description">The closing days of the conference</div>
            </div>
            </div>
            </body>
            </html>
            

在 Web 瀏覽器中查看此文件時,顯示效果如 圖 2 所示。


圖 2. hcalendar.html 頁面
hcalendar.html 頁面

這看上去并不美觀,但我只是想讓這個示例盡可能地簡單。關鍵在于您可以使用希望的任何 HTML 樣式,使卡片顯示為您喜歡的任何外觀。只要使用了正確的 CSS 類名,它仍然會被識別為一個微格式化的 hCalendar 條目。

既然已經有了頁面,我需要一些 PHP 代碼來讀取此頁面。清單 3 顯示了此代碼,這是讀取腳本的基礎。


清單 3. get_page 函數
<?php
            require_once 'HTTP/Client.php';
            function get_page( $url )
            {
            $client = new HTTP_Client();
            $client->get( $url );
            $resp = $client->currentResponse();
            return $resp['body'];
            }
            

此代碼使用 HTTP Client PEAR 模塊從給定 URL 讀取內容。如果您還沒有安裝該模塊,可以使用 PEAR 命令行來安裝:

% pear install HTTP_Client
            

接下來,我將站點返回的 HTML 轉換成一個 XML Document Object Model(DOM)。謝天謝地,站點返回的 HTML 是 Extensible HTML(XHTML),因此使一個 XML 閱讀器指向它非常簡單。我利用 清單 4 中的 get_events() 函數完成這個任務。


清單 4. get_events 函數
function get_events( $page )
            {
            $body = get_page( $page );
            $dom = new DomDocument();
            $dom->loadXML( $body );
            $xpath = new DOMXPath( $dom );
            $events = $xpath->query("//div[@class='vevent']");
            $parsed_events = array();
            foreach( $events as $event )
            {
            $e = parse_event( $dom, $event );
            $parsed_events []= $e;
            }
            return $parsed_events;
            }
            

此函數首先調用 get_page() 函數來檢索頁面內容。隨后創建并加載 DomDocument() 函數。得到了 DOM 版本后,我使用 XPath 查詢來獲得出現 vevent 類的頁面上的所有 <div> 標記,并將那些節點傳遞給 parse_event。

如果您不熟悉 XPath,我將為您略加分析。表達式:

//div
            

將匹配任何級別的 <div> 標記。添加如下約束:

//div[@class='vevent']
            

這樣就僅匹配具有一個名為 class 的屬性、且其本身具有與 vevent 相匹配的值的 <div> 標記。如果您使用 XML 或一種基于 XML 的語言(例如 XHTML 或 RSS),您應該對 XPath 比較熟悉。XPath 是迄今為止導航 XML 樹并獲得您尋找的信息的最簡單的方法。

為了獲得各事件 <div> 標記中的數據,parse_event 類使用了更多的 XPath 查詢來提取這些數據。如 清單 5 所示。


清單 5. parse_event() 函數
function parse_event( $dom, $event )
            {
            $data = array();
            $xpath = new DOMXPath( $dom );
            $url = $xpath->query( ".//*[contains(@class,'url')]/@href", $event );
            $data['url'] = $url->length > 0 ? $url->item(0)->nodeValue : ';
            $dtstart = $xpath->query( ".//*[contains(@class,'dtstart')]/@title", $event );
            $data['dtstart'] = $dtstart->length > 0 ? $dtstart->item(0)->nodeValue : ';
            $dtend = $xpath->query( ".//*[contains(@class,'dtend')]/@title", $event );
            $data['dtend'] = $dtend->length > 0 ? $dtend->item(0)->nodeValue : ';
            $summary = $xpath->query( ".//*[contains(@class,'summary')]", $event );
            $data['summary'] = $summary->length > 0 ? $summary->item(0)->nodeValue : ';
            $location = $xpath->query( ".//*[contains(@class,'location')]", $event );
            $data['location'] = $location->length > 0 ? $location->item(0)->nodeValue : ';
            $desc = $xpath->query( ".//*[contains(@class,'description')]", $event );
            $data['desc'] = $desc->length > 0 ? $desc->item(0)->nodeValue : ';
            return $data;
            }
            

代碼看上去有點復雜,但實際上這只是一組 XPath 查詢,在 XML DOM 樹中查找具有特定類名的特定標記。而這種 XPath 編碼更為復雜,首先,其中有一個符號:

.//*
            

該符號表示 “從這里 開始往下的所有標記”,其中的這里 也就是代碼當前看到的 <event> 標記。請注意,$xpath->query 語句現指定了一個附加的參數 $event,這是搜索的根。典型情況下,XPath 查詢從文檔根處開始,但您可指定其他根。為此,我使用了 $event 條目。

現在,我并不想獲得所有標記。我想要的只是一個具有某個屬性的標記,該屬性名為 class,并包含一個特定的值(例如 url)。因此,我添加了如下語法:

.//*[contains(@class,'url')]
            

這樣它就會匹配類名中包含 url 的標記。但我真正想獲得的是該標記中的 href 屬性,所以我進一步精煉了此查詢,方法如下:

.//*[contains(@class,'url')]/@href
            

精煉過的這個查詢將獲取任何匹配標記的 href 屬性。

事件完成并作為來自 get_events() 函數的數組返回后,我還需要另外一個函數,將這個事件數組導出為 XML。為此,我使用了 dump_events() 函數,如 清單 6 所示。


清單 6. dump_events() 函數
function dump_events( $events )
            {
            $dom = new DomDocument();
            $dom->formatOutput = true;
            $root = $dom->createElement( 'events' );
            $dom->appendChild( $root );
            foreach( $events as $event )
            {
            $elEvent = $dom->createElement( 'event' );
            $root->appendChild( $elEvent );
            $elUrl = $dom->createElement( 'url' );
            $elUrl->appendChild( $dom->createTextNode( $event['url'] ) );
            $elEvent->appendChild( $elUrl );
            $elStart = $dom->createElement( 'start' );
            $elStart->appendChild( $dom->createTextNode( $event['dtstart'] ) );
            $elEvent->appendChild( $elStart );
            $elEnd = $dom->createElement( 'end' );
            $elEnd->appendChild( $dom->createTextNode( $event['dtend'] ) );
            $elEvent->appendChild( $elEnd );
            $elSummary = $dom->createElement( 'summary' );
            $elSummary->appendChild( $dom->createTextNode( $event['summary'] ) );
            $elEvent->appendChild( $elSummary );
            $elLocation = $dom->createElement( 'location' );
            $elLocation->appendChild( $dom->createTextNode( $event['location'] ) );
            $elEvent->appendChild( $elLocation );
            $elDesc = $dom->createElement( 'description' );
            $elDesc->appendChild( $dom->createTextNode( $event['desc'] ) );
            $elEvent->appendChild( $elDesc );
            }
            print( $dom->saveXML() );
            }
            

此函數與其他函數背道而馳。這段代碼不是圍繞某些 XML 進行查詢,而是使用 createElementappendElement 創建一個樹,從而創建了一個 DOM。隨后,我使用 saveXML 命令將數據導出到標準輸出。

在命令行中使用 hcalendar.html 頁面的 URL 運行這個 PHP 腳本時,我得到了 清單 7 所示的輸出結果。


清單 7. PHP 腳本的輸出結果
% php get_calendar.php http://localhost/micro/hcalendar.html
            <?xml version="1.0"?>
            <events>
            <event>
            <url>http://myevent.com</url>
            <start>20060501</start>
            <end>20060502</end>
            <summary>My Conference opening</summary>
            <location>Hollywood, CA</location>
            <description>The opening days of the conference</description>
            </event>
            <event>
            <url>http://myevent.com</url>
            <start>20060503</start>
            <end>20060504</end>
            <summary>My Conference closing</summary>
            <location>Hollywood, CA</location>
            <description>The closing days of the conference</description>
            </event>
            </events>
            %
            

現在我有了一個腳本,可以指向任何 Web 頁面,并將任何 hCalendar 格式的條目提取為 XML。





回頁首


通過 XML 創建 hCalendar 條目

既然已經有了從 Web 頁面中提取出來的 XML,那么就可以創建一個 PHP 頁面,將此 XML 格式化為 HTML 內的 hCalendar 條目。清單 8 顯示了此頁面。


清單 8. Index.php
<?php
            $dom = new DomDocument();
            $dom->load( "calendar.xml" );
            $xpath = new DomXPath($dom);
            $events = $xpath->query( '//event' );
            ?>
            <html>
            <head>
            <title>My Calendar</title>
            <style>
            body { font-family: arial, verdana, sans-serif; }
            td { border-bottom: 1px solid black; border-top: 1px solid black; }
            abbr { border-bottom: none; }
            </style>
            </head>
            <body>
            <table>
            <?php
            foreach( $events as $event )
            {
            $desc = $xpath->query( 'description', $event )->item(0)->nodeValue;
            $start= $xpath->query( 'start', $event )->item(0)->nodeValue;
            $end = $xpath->query( 'end', $event )->item(0)->nodeValue;
            $location = $xpath->query( 'location', $event )->item(0)->nodeValue;
            $summary = $xpath->query( 'summary', $event )->item(0)->nodeValue;
            $url = $xpath->query( 'url', $event )->item(0)->nodeValue;
            ?>
            <tr>
            <td>
            <div class="vevent">
            <a class="url" href="<?php echo( $url ); ?>">
            <span class="summary"><?php echo($summary ); ?></span></a><br/>
            Start: <abbr class="dtstart" title="<?php echo($start ); ?>">
            <?php echo($start ); ?></abbr><br/>
            End: <abbr class="dtend" title="<?php echo($end ); ?>">
            <?php echo($end ); ?></abbr><br/>
            Location: <span class="location"><?php echo($location ); ?></span><br/>
            <div class="description"><?php echo($desc ); ?></div>
            </div>
            </td>
            </tr>
            <?php
            }
            ?>
            </table>
            </body>
            </html>
            

這段代碼似乎有些復雜,但實際上非常簡單。加載前面使用 get_calendar.php 腳本創建的 calendar.xml 文件來啟動頁面。頁面隨后啟動 HTML,直至 <table> 標記。在此標記中,我循環遍歷了各個 <event> 標記,并將它們導出為 HTML 中的行。這樣,就完成了 Web 頁面。圖 3 顯示了最終結果。


圖 3. index.php 頁面
Index.php 頁面

為了查看這段代碼是否確實編碼了 hCalendar 條目,我將 get_calendar.php 腳本指向它。清單 9 顯示了結果。


清單 9. 事件 XML 片段
% php get_calendar.php http://localhost/micro/index.php
            <?xml version="1.0"?>
            <events>
            <event>
            <url>http://myevent.com</url>
            <start>20060501</start>
            <end>20060502</end>
            <summary>My Conference opening</summary>
            <location>Hollywood, CA</location>
            <description>The opening days of the conference</description>
            </event>
            ...
            %
            

這有多好呢?我有了一個腳本,能讀取帶有日歷條目的頁面并將這些條目導出為 XML。然后我又有了另外一個頁面,能將 XML 轉換回日歷條目。隨后原始腳本可以讀取該頁面并獲得相同的數據。這最終變成了一個無休無止的循環。

好吧,或許這不怎么樣。也不怎么美觀。如果我想讓顯示效果更美觀一點,會怎么樣呢?我是否必須轉儲微格式?完全不需要。在 清單 10 中,我改進了日歷條目的格式。


清單 10. Index2.php
...
            <?php
            foreach( $events as $event )
            {
            $desc = $xpath->query( 'description', $event )->item(0)->nodeValue;
            $start= $xpath->query( 'start', $event )->item(0)->nodeValue;
            $end = $xpath->query( 'end', $event )->item(0)->nodeValue;
            $location = $xpath->query( 'location', $event )->item(0)->nodeValue;
            $summary = $xpath->query( 'summary', $event )->item(0)->nodeValue;
            $url = $xpath->query( 'url', $event )->item(0)->nodeValue;
            ?>
            <tr>
            <td class="event">
            <div class="vevent">
            <table width="100%" cellspacing="0" cellpadding="0">
            <tr>
            <td colspan="2">
            <a class="url" href="<?php echo( $url ); ?>">
            <span class="summary"><?php echo($summary ); ?></span></a>
            </td>
            </tr>
            <tr>
            <td>Start</td>
            <td><abbr class="dtstart" title="<?php echo($start ); ?>">
            <?php echo($start ); ?></abbr></td>
            </tr>
            <tr>
            <td>End</td>
            <td><abbr class="dtend" title="<?php echo($end ); ?>">
            <?php echo($end ); ?></abbr></td>
            </tr>
            <tr>
            <td>Location</td>
            <td><span class="location"><?php echo($location ); ?></span></td>
            </tr>
            <tr>
            <td colspan="2">
            <div class="description"><?php echo($desc ); ?></div>
            </td>
            </tr>
            </table>
            </div>
            </td>
            </tr>
            <?php
            }
            ?>
            ...
            

也許您很難從這些標簽中發現有什么改變,但從顯示效果中能清楚地看出差別,如 圖 4 所示。


圖 4. index2.php 頁面
Index2.php 頁面

現在,start、endlocation 列排列得非常美觀。但它是否仍然解析為 hCalendar 條目?是的,原因在于 get_calendar.php 腳本中的 XPath 代碼極為靈活。

清單 11 展示了我為證明上述問題而運行的測試。


清單 11. 對 index2.php 的測試
% php get_calendar.php http://localhost/micro/index2.php
            <?xml version="1.0"?>
            <events>
            <event>
            <url>http://myevent.com</url>
            <start>20060501</start>
            <end>20060502</end>
            ...
            

我真的非常喜歡這兩個讀取和寫入腳本之間的對稱。





回頁首


結束語

微格式是一種注重實效的方法,解決了 Web 上結構化數據的問題。從架構上來看,它是否純粹是通過 XSLT 樣式表這樣的機制與格式相分離的 XML 編碼數據?并非如此。但我認為這種方法是一種實際的中間步驟,能夠幫助您構建起更為智能化的 Web,更易于使用,并且能夠提供更好的搜索和數據集成。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97