使用 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 頁面的定位點。dtstart
和 dtend
類位于 title 元素中編碼了開始時間和結束時間的標記內。summary
、location
和 description
類均屬于包含相應內容的標記。
現在,這些條目所在的頁面即可使用 CSS 任選方式來編碼這些條目了。因此,卡片的外觀對于站點來說依然是惟一的。類的命名規范才是最重要的。
這就是微格式要處理的全部。微格式的 Web 站點就像是一個維基百科,您可為想展示的任何數據添加您自己的格式。在我上一次查看該站點時,那里有用于事件、聯系信息、評論及其他許多方面的格式。站點中甚至還提供了一個方便的格式創建程序,如 圖 1 所示。
圖 1. 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 頁面
這看上去并不美觀,但我只是想讓這個示例盡可能地簡單。關鍵在于您可以使用希望的任何 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>
標記。添加如下約束:
這樣就僅匹配具有一個名為 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 進行查詢,而是使用 createElement
和 appendElement
創建一個樹,從而創建了一個 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 頁面
為了查看這段代碼是否確實編碼了 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 頁面
現在,start、end 和 location 列排列得非常美觀。但它是否仍然解析為 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
|