xml,Atom是什么

          Posted on 2007-12-07 21:30 yukui 閱讀(4035) 評論(0)  編輯  收藏 所屬分類: 技術(shù)

          Atom 是一種格式還是一種協(xié)議?兩者都是!將其用于聯(lián)合和發(fā)布

           

           



          級別: 中級

          Dethe Elza (delza@livingcode.org), 技術(shù)架構(gòu)師, Justsystems
          David Mertz (mertz@gnosis.cx), 作者, Gnosis Software, Inc.

          2006 年 10 月 27 日

          Atom 實(shí)際上是兩種不同的、都與聯(lián)合(blog、新聞提要和其他定期更新的信息)有關(guān)的東西。Atom Syndication Format 是用于發(fā)布條目(單個主題或者項(xiàng))和提要(主題或項(xiàng)的集合)的 IETF 標(biāo)準(zhǔn)。Atom Publication Protocol(有時候稱為 Atom API 或縮寫為 APP)是從 Atom 資料庫中發(fā)現(xiàn)、列表、添加、編輯和刪除內(nèi)容的方法。盡管作為聯(lián)合格式的 Atom 已經(jīng)通過 IETF 審查成為一項(xiàng)標(biāo)準(zhǔn),但標(biāo)準(zhǔn)委員會仍然在研究作為發(fā)布協(xié)議的 Atom,雖然目前來看大部分似乎已經(jīng)確定。

          開始學(xué)習(xí) Atom 激動人心的所有方面。

          Atom 聯(lián)合

          作為一種聯(lián)合格式,Atom 來源于各種 RSS(有很多)的實(shí)踐而不是完全從頭創(chuàng)建的,只不過明確了 RSS 規(guī)范中含糊的地方使其更有用(比如 RSS 沒有規(guī)定 title 元素能否包含標(biāo)記),改正有問題的一些地方(比如確定不同提要中的重復(fù)項(xiàng),這種情況在聚合內(nèi)容中經(jīng)常出現(xiàn))。原來用于 RSS 提要的多數(shù)客戶機(jī)和工具現(xiàn)在都支持或準(zhǔn)備支持 Atom 內(nèi)容,既然它解決了 RSS 中存在的問題,我推薦使用這種格式。但基本上來說 Atom 是對 RSS 的逐步改進(jìn)而不是革命性的改造。Atom 采取的一個演化步驟是支持兩種基本類型的聯(lián)合文檔:提要和項(xiàng)。提要與 RSS 類似,都是項(xiàng)的集合。但項(xiàng)也可以是獨(dú)立的文檔,本身包含一張?zhí)樱赡苁且粭l新聞或者 blog 貼子)或者對外部文檔的引用,比如圖片。優(yōu)于兩者兼?zhèn)洌赃@種聯(lián)合格式為建立發(fā)布協(xié)議提供一個靈活的層面。

          清單 1 顯示了 ATom 提要的一個小例子:


          清單 1. Atom 提要
          <?xml version='1.0' encoding='UTF-8'?>
                                  <feed xmlns='http://www.w3.org/2005/Atom'>
                                  <id>urn:uuid:E14A6C6B-A832-4AE9-9D67-263181407D5E</id>
                                  <link rel="self" href="/temp/index.atom"/>
                                  <updated>2006-04-19T18:43:55Z</updated>
                                  <title type='text'>Cool gizmos</title>
                                  <subtitle type='text'>The latest in high-tech gizmos.</subtitle>
                                  <author>
                                  <name>Dethe Elza</name>
                                  <email>dethe.elza@livingcode.org</email>
                                  </author>
                                  <entry>
                                  <id>urn:uuid:2C31F522-20A6-44DF-AA63-6524441FF6A3</id>
                                  <published>2006-05-02T19:00:10Z</published>
                                  <updated>2006-04-30T20:57:20Z</updated>
                                  <title type='text'>This new gizmo is hot, hot hot!</title>
                                  <content type='text'>I just got my hands on the latest gizmo
                                  that's sweeping the nation: it's totally rad.</content>
                                  </entry>
                                  </feed>
                                  





          回頁首


          協(xié)議、更多的協(xié)議和 API

          作為發(fā)布協(xié)議,Atom 具有更大的抱負(fù)。曾經(jīng)嘗試過幾次創(chuàng)建管理 Web 內(nèi)容(比如 blog)的通用協(xié)議(盡管常常被誤稱為 API),但要么缺少必要的功能,要么需要工作區(qū)或者私有接口。最重要的是,這些嘗試都沒有利用好的 Web 應(yīng)用實(shí)踐,如 REST。LiveJournal 是第一次嘗試,但是它把一切都通過 HTTP POST 傳輸而忽略了 GET、PUT 和 DELETE,也沒有使用 HTTP 身份驗(yàn)證。XML-RPC 也走了同樣的路線,與 LiveJournal 協(xié)議一樣通過 URI 發(fā)送所有信息。直到最近,XML-RPC 還將字符串限制為 ASCII,因而首先就放棄了 XML 的主要優(yōu)點(diǎn)之一。雖然 XML-RPC 本身不是一個發(fā)布協(xié)議,但一些協(xié)議是以它為基礎(chǔ)的,包括 Manila RPC、Blogger API、MetaWeblog API 以及 LiveJournal XML-RPC Client/Server 協(xié)議。這些協(xié)議都不支持國際化,都使用明文傳遞口令,都不容易擴(kuò)展。Atom Publishing Protocol 充分利用了 XML(國際化,可使用 XML 名稱空間擴(kuò)展)和 HTTP(所有的方法、身份驗(yàn)證、用 URI 標(biāo)識資源)。

          Atom Publishing Protocol 以 weblog 協(xié)議為基礎(chǔ)但又超越了 weblog 協(xié)議,是一種管理 Web 內(nèi)容的方便工具,得到很多應(yīng)用,其中包括 Bugzilla、Google Data APIs Protocol 以及 上一期 “XML 問題” 文章(請參閱 參考資料)中提到的很多日程安排站點(diǎn),還有一個當(dāng)時沒有提到但下面就要討論的重要站點(diǎn)。

          我認(rèn)為 Atom Publishing Protocol 是通往可寫入 Web 的征途中的一個重要里程碑。從來 Web 都是雙向的,PUT 和 DELETE 方法一直是 HTTP 的一部分,但在讀/寫 Web 的前進(jìn)途中出了岔子。我們已經(jīng)通過 wiki、XML-RPC 和大塊頭 WebDAV 緩慢地轉(zhuǎn)回原來的 Web 之路。WebDAV 或簡稱 DAV,即分布式編輯和版本協(xié)議(Distributed Authoring and Versioning),其目標(biāo)是 “完成 Web 的最初目標(biāo),成為一種可寫的、協(xié)作媒介”(引自 WebDAV FAQ)。因此將 APP 與 DAV 進(jìn)行對比是公平的。DAV 提供的功能遠(yuǎn)遠(yuǎn)超過 APP,包括阻塞、任意元數(shù)據(jù)的存儲以及存儲資源的刪除或重命名。公平地說,Atom 也能支持任意元數(shù)據(jù),因?yàn)楹苋菀淄ㄟ^ XML 名稱空間擴(kuò)展。Atom 實(shí)際上對協(xié)作的支持比較弱,只有發(fā)布(包括以后的編輯),因此對阻塞的需要不大,而且可以用 DELETE 后跟 PUT 來對資源重命名。Atom 完成這些功能不需要擴(kuò)展 HTTP 或者增加新的方法。WebDAV 極其復(fù)雜,一直受到主供應(yīng)商糟糕的、漏洞百出的實(shí)現(xiàn)的困擾。即便如此,WebDAV 社區(qū)仍然不滿足 DAV 對 HTTP 的擴(kuò)展,因此又層層加碼(或者準(zhǔn)備)作進(jìn)一步的擴(kuò)展,比如 Advanced Collections、Versioning and Configuration Management(因?yàn)槟溃珼istributed Authoring and Versioning 不支持版本化)和 Access Control。但是這些擴(kuò)展對日程安排來說還不夠,因此出現(xiàn)了 CalDAV,它對 HTTP 做了更多擴(kuò)展。

          可能毫不奇怪,WebDAV 一直未能成功地征服 Web。難以實(shí)現(xiàn),而且設(shè)置和管理都很麻煩。DAV 也有自己的成功支持,特別是 Subversion,這個版本控制系統(tǒng)被夸耀成 CVS 的后繼者。Subversion 建立在 DAV 和 Versioning 擴(kuò)展(也稱為 DeltaV)的基礎(chǔ)上,雖然它僅僅選擇 DAV 中相關(guān)的部分而丟掉了其他功能,然后在這個混合物中加上自己的協(xié)議。雖然 Subversion 很成功,但是它實(shí)際上沒有證明 DAV 巴洛克式的復(fù)雜性的正確性。對于 DAV 功能中的 90%,我認(rèn)為 APP 更合適,剩下的 10% 可放到其他系統(tǒng)中。APP 本身并不是一個包羅萬象的終極解決方案。它本身沒有解決身份驗(yàn)證的問題,沒有提供查詢機(jī)制,當(dāng)然也沒有支持實(shí)時協(xié)作這類功能的打算。我認(rèn)為讀/寫式 Web 仍在成長之中,我期望也許有一天 Jabber XMPP 協(xié)議會嵌入到 Web 瀏覽器中作為雙向?qū)崟r端對端協(xié)議,但這是后話了。

          James Tauber 正在從事一個與 Atom 和 Subversion 有關(guān)的 Python 項(xiàng)目,稱為 Demokritos,該項(xiàng)目提供了 Atom Store。有趣的地方(至少對于本文來說)在于底層使用 Subversion 來提供持久性。項(xiàng)目仍然處在早期階段(今后的版本將增加身份驗(yàn)證),但是值得關(guān)注其進(jìn)展。Google Base 可以看作是 Atom Store 的商業(yè)版本(雖然多數(shù)上傳使用現(xiàn)在已經(jīng)過時的 Atom Syndication Format 0.3 版),Amazon 的 S3 數(shù)據(jù)存儲從使用 HTTP GET/PUT/DELETE 這一點(diǎn)看在概念上類似于 Atom Publishing Protocol。有選擇當(dāng)然好,但是如果所有的選擇都統(tǒng)一到一個簡單、健壯的標(biāo)準(zhǔn)上就更好了。

          Atom Publishing Protocol 的工作原理是,客戶機(jī)可以查詢自省(introspection)文檔,這類文檔列出了提供的內(nèi)容集合、能力(比如可讀和可寫)及其地址 URI。然后客戶機(jī)可以查詢集合本身來發(fā)現(xiàn)與其自身包含的內(nèi)容類似的信息,可以是 Atom Entries 或圖片、音頻、視頻之類的媒體。集合是 Atom 提要,增加新的材料只需要 PUT 一個 Atom Entry 文檔并收到指向該資源的 URI,然后可以對該資源作進(jìn)一步處理(用 POST 編輯,用 GET 讀,用 DELETE 刪除)。比如,清單 2 是一個簡單的自省文檔:


          清單 2. 自省文檔的例子
          <?xml version="1.0" encoding='utf-8'?>
                                  <service xmlns="http://purl.org/atom/app#">
                                  <workspace title="Gizmo Page" >
                                  <collection
                                  title="Cool gizmos"
                                   >
                                  <member-type>entry</member-type>
                                  </collection>
                                  <collection
                                  title="Photos of Gizmos"
                                   >
                                  <member-type>media</member-type>
                                  </collection>
                                  </workspace>
                                  </service>
                                  

          這個自舉過程中仍然有一個問題:一開始如何發(fā)現(xiàn)自省文檔?有一個雖然過期但是廣泛實(shí)現(xiàn)的 IETF 草案 Atom Feed Autodiscovery,它描述了如何在 HTML 頁面的元數(shù)據(jù)中嵌入一個或多個 Atom 提要引用。該方法對自省文檔也同樣有效。這項(xiàng)技術(shù)很簡單,在 HTML 文檔的 <head> 中插入一個 <link> 元素,其 rel 屬性包含關(guān)鍵字 “alternate”,type 屬性值為 “application/atom+xml”,href 屬性指向一個 Atom 提要。雖然 Atom 工作組沒有明確說明這種方法如何用于自省文檔,但大致與上述形式類似,只不過如 Atom wiki 上所述作以下變更:rel 屬性為 “introspection”,type 屬性必須是 “application/atomserv+xml”,href 則指向一個自省文檔而不是提要。無論哪種情況,<link> 元素都應(yīng)該在 title 屬性中包含人類可讀的值。比如:

          <link rel="instrospection" type="application/atomserv+xml"
                                  href="/introspection.atomsrv" title="All about my feeds"/>
                                  





          回頁首


          為什么 Atom 必須支持微格式?

          上一期 “XML 問題” 文章中,我提到只有與 Atom 結(jié)合起來微格式才能真正得到應(yīng)用(請參閱 參考資料)。這句話現(xiàn)在仍然有效。Uche Ogbuji 是一位 Atom 擁躉,但是對微格式的使用持不同意見。專門針對 Atom 的微格式目前有兩種(據(jù)我所知):hAtom 是 Atom 的一個子集,此外還有關(guān)于 “XHTML Microformats for the Atom Publishing Protocol” 的一個 IETF 草案,它提出了兩種微格式用于在 APP 中描述類別和錯誤。我還沒有發(fā)現(xiàn)這些微格式的應(yīng)用。

          最有趣的是,微格式是用于嵌入其他文檔的,而 Atom 文檔的目的是包含 HTML 或 XHTML 片段(以小心控制的方式)。因此沒有理由 Atom 提要中不能嵌入 hCalendar 制定的日歷。事實(shí)上,就在上一篇文章進(jìn)入最終編輯階段時,Google 發(fā)布了它的 Calendar 產(chǎn)品,該產(chǎn)品允許以 Atom 格式訂閱日歷提要。不幸的是,雖然能夠以包含 iCalendar 信息的方式獲得提要,但 Google 沒有在提要中提供 hCalendar。一些人注意到了這一點(diǎn),編寫了 GreaseMonkey 腳本之類的東西在網(wǎng)頁中發(fā)現(xiàn) hCalendar 并將其增加到 Google Calendar 中,但我希望選擇另一條路,使用我的 Google Calendar Atom 提要向 hCalendar 格式的 weblog 增加事件。快速搜索后沒有發(fā)現(xiàn)別人做過這個,我只好自己寫了一個簡單、粗糙的腳本。我是用 Python 編寫的,它需要兩個第三方庫:httplib2 和 ElementTree,鏈接參見 參考資料。這僅僅是個例子,與一般的例子一樣沒有包含錯誤檢查,也不是很靈活。清單 3 顯示了示范其用法的測試函數(shù):


          清單 3. Atom 到 weblog 的腳本
          '''
                                  Utility to grab a Google Calendar feed and return hCalendar code
                                  This module has one public function:
                                  events_for_feed(feed_uri, start, end) -> [hCalendarEvents]
                                  '''
                                  import StringIO
                                  import httplib2
                                  import cElementTree
                                  _ATOM_NS = 'http://www.w3.org/2005/Atom'
                                  _GDATA_NS = 'http://schemas.google.com/g/2005'
                                  _MONTHS = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
                                  'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
                                  _EVENT_TEMPLATE = '''<div class="vevent"
                                  xmlns="http://www.w3.org/1999/xhtml">
                                  <abbr class="dtstart" title="%(start)s">%(start_hr)s</abbr> -
                                  <abbr class="dtend" title="%(end)s">%(end_hr)s</abbr> -
                                  <span class="summary">%(summary)s</span> - at
                                  <span class="location">%(where)s</span>
                                  <div class="description">%(description)s</div>
                                  </div>
                                  '''
                                  def _end_human_readable(ts):
                                  return ts[11:16]
                                  def _start_human_readable(ts):
                                  month = _MONTHS[int(ts[5:7], 10)]
                                  return '%s %s, %s - %s' % (month, ts[8:10], ts[:4], ts[11:16])
                                  def _entries_for_feed(feed_uri, start, end):
                                  h = httplib2.Http('.cache')
                                  resp, content = h.request('%s?start-min=%s&start-max=%s' %
                                  (feed_uri, start, end), 'GET')
                                  doc = cElementTree.parse(StringIO.StringIO(content))
                                  return doc.findall('//{%s}entry' % _ATOM_NS)
                                  def _event_for_entry(entry):
                                  when = entry.find('{%s}when' % _GDATA_NS)
                                  start = when.get('startTime')
                                  start_hr = _start_human_readable(start)
                                  end = when.get('endTime')
                                  end_hr = _end_human_readable(end)
                                  where = entry.find('{%s}where' % _GDATA_NS).get('valueString')
                                  summary = entry.findtext('{%s}title' % _ATOM_NS)
                                  description = entry.findtext('{%s}content' % _ATOM_NS)
                                  return locals().copy()
                                  def events_for_feed(feed_uri, start, end):
                                  return [_EVENT_TEMPLATE % _event_for_entry(entry) for entry in
                                  _entries_for_feed(feed_uri, start, end)]
                                  def test():
                                  feed_uri = 'http://www.google.com/calendar/feeds/\
                                  dethe.elza@gmail.com/public/full'
                                  start = '2006-04-30T00:00:00'
                                  end = '2006-05-30T00:00:00'
                                  for event in events_for_feed(feed_uri, start, end):
                                  print event
                                  if __name__ == '__main__':
                                  test()
                                  

          將該腳本增加到 Calendar 提要中并提供起始日期和結(jié)束日期,就會返回一列 hCalendar 格式的字符串,可以插入到 weblog 中。這就是讀/寫式 Web 的優(yōu)美之處。如果某一方不支持您的格式,但是他們使用的格式是開放的并提供相應(yīng)文檔,就像 google 那樣,您可以根據(jù)需要自行創(chuàng)建。我的觀點(diǎn)是,微格式和 Atom 是互不可分的,這一觀點(diǎn)雖然還沒有得到證實(shí),但至少以不同的方式說明了兩者可以協(xié)同工作(仍然有很多工作要做)。





          回頁首


          結(jié)束語

          關(guān)于 Atom Publication Protocol 的研究仍在繼續(xù),其他相關(guān)規(guī)范如 Google Calendar 擴(kuò)展同樣如此。網(wǎng)站在快速地采用 Atom,應(yīng)用程序和編程工具也在適應(yīng) Atom。開放的格式、可擴(kuò)展性和清晰的定義,使得 Atom 對于 Web 影響力有可能像關(guān)系數(shù)據(jù)庫對企業(yè)一樣。HTTP GET 和 View Source 時至今日仍然是一種有效的組合,就像在 Web 早期一樣。

          通過這篇簡短的介紹,我希望您能了解 Atom Syndication 格式的重要性以及 Atom Publication Protocol 如何簡化它的使用。要進(jìn)一步了解如何使用這些新技術(shù),請參閱 參考資料



          參考資料

          學(xué)習(xí)
          • 您可以參閱本文在 developerWorks 全球網(wǎng)站上的 英文原文

          • XML 問題:管道流微格式”(developerWorks,2006 年 4 月):結(jié)合管道和流將 XML 從一種狀態(tài)轉(zhuǎn)變?yōu)榱硪环N狀態(tài)。

          • Atom 1.0 Syndication Format 概述”(2005 年 8 月):關(guān)于 Atom 的詳細(xì)介紹請參閱 James Snell 撰寫的這篇 IBM developerWorks 文章。

          • Atom Syndication Format:閱讀 Atom 文檔的正式 IETF 規(guī)范,官方稱為 RFC 4287。

          • Atom Publishing Protocol:請閱讀該規(guī)范的當(dāng)前 IETF 草案(revision 11)。

          • Atom Feed Autodiscovery:這份過期的 IETF 草案描述了對 Atom 提要和自省文檔的嵌入式引用。

          • Extensible Messaging and Presence Protocol (XMPP):研讀 IETF 對 XML 路由核心協(xié)議的形式化,這是 Jabber 即時消息系統(tǒng)的核心。

          • RSS and Atom compared:該文概括了 Atom Syndication Format 與 RSS 2.0 相比的優(yōu)點(diǎn)。

          • Atom Publishing Protocol Slides:重溫 Joe Gregorio 在 XML 2005 關(guān)于 Atom 要解決的問題所作的演講(包括聯(lián)合格式和發(fā)布協(xié)議)。

          • Bugzilla Query RSS should HTML-escape summary in <title>”:閱讀 Bugzilla 上的缺陷討論,泄露了讓 Bugzilla 團(tuán)隊(duì)轉(zhuǎn)向 Atom 的 RSS 局限性。

          • Dreaming of an Atom Store”:細(xì)讀 Joe Gregorio 結(jié)合使用 Atom Publishing Protocol 和 Amazon Open Search 的觀點(diǎn)。

          • Open Search:看看 Amazon A9 搜索工具的一部分,它允許聚合搜索結(jié)果。可以得到 HTML、RSS 或 Atom 格式的搜索結(jié)果。

          • Google Data APIs:看看 Google Atom Store 如何在 Atom Publishing Protocol 的基礎(chǔ)上增加了身份驗(yàn)證、優(yōu)化并發(fā)訪問和查詢功能。

          • Google Calendar Data API:查看 Google 的查詢 URL 格式化及其訪問日歷數(shù)據(jù)的 Java 庫文檔。

          • Atom Enabled:訪問這個介紹 Atom 的網(wǎng)站,它提供了到使用 Atom 的庫、客戶機(jī)和服務(wù)的鏈接。

          • WebDAV Resources:這是學(xué)習(xí) WebDAV 的一個很好的起點(diǎn)。

          • The Atom Project Wiki”:這個 Wiki 上列出了原來稱為 Pie 的聯(lián)合格式和發(fā)布協(xié)議的問題。

          • Microformats in Context”:Uche Ogbuji 討論了微格式的優(yōu)缺點(diǎn)。

          • XHTML Microformats for the Atom Publishing Protocol”:這份 IETF 草案描述用于 Atom 類別的 hCat 和用于 Atom 錯誤的 hError。

          • hAtom:進(jìn)一步了解作為 Atom 本身子集的這種微格式。

          • Google Base:看看它與 Joe Gregorio 在 上面文章 中所述的 Atom Store 多么相似。

          • Amazon S3: Simple Storage Service”:雖然不是 Atom Store,但是概念上類似,它還支持 BitTorrent 下載。與 Amazon A9 搜索結(jié)合起來,后者能夠用 Atom 提要返回搜索結(jié)果,非常有趣。


          獲得產(chǎn)品和技術(shù)
          • Universal Feed Parser:該 Python 程序能夠解析所有已知的 RSS 和 Atom 格式,主要目標(biāo)是最大可能地提取數(shù)據(jù)而不是保證格式的有效性,就是說能夠解析很多嚴(yán)格來說不正確的提要。

          • Joe Gregorio 的 Python 庫 Httplib2(客戶端 HTTP):支持 HTTP 1.1、HTTPS、三種 HTTP Authentication 形式、緩沖、壓縮、所有 HTTP 方法等。

          • Subversion:這種版本控制工具使用 WebDAV 為 CVS 提供了遞增式改進(jìn)。

          • Demokritos:James Tauber 的 Atom Store 用 Python 編寫,使用 Subversion 持久。

          • Feed Validator:檢查(您或者別人的)Atom 提要中的錯誤。

          • Atom Publishing Protocol Test Suite:檢查支持 APP 的站點(diǎn)是否遵循該協(xié)議。(包括 HTTP 身份驗(yàn)證。)

          • ElementTree:Frederik Lundh 開發(fā)的 Python XML 庫。


          作者簡介

          Dethe Elza 的照片

          Dethe Elza 最喜歡的職位是首席瘋狂科學(xué)家(Chief Mad Scientist)。可以通過 delza@livingcode.org 與 Dethe 聯(lián)系。他有自己的博客 http://livingcode.org/,主要是關(guān)于 Python 和 Mac OS X 的,他為自己的孩子編寫程序。歡迎對本專欄提供建議和意見。


          David Mertz 的照片

          David Mertz 是一位開放標(biāo)準(zhǔn)的虔誠信奉者,僅對這類標(biāo)準(zhǔn)的冗長略有微詞。可以通過 mertz@gnosis.cx 與 David 聯(lián)系,在 http://gnosis.cx/dW/ 上有關(guān)于他的生活的詳細(xì)介紹。歡迎對本文、以前及將來的專欄文章提出建議和意見。請閱讀 David 的著作 Text Processing in Python

          posts - 131, comments - 12, trackbacks - 0, articles - 32

          Copyright © yukui

          主站蜘蛛池模板: 清镇市| 石首市| 晋宁县| 巫山县| 静宁县| 清河县| 屏东市| 武功县| 中山市| 淮滨县| 嵊州市| 交口县| 定日县| 宁国市| 太仆寺旗| 斗六市| 儋州市| 保定市| 咸丰县| 承德市| 五华县| 藁城市| 樟树市| 中方县| 连山| 正镶白旗| 进贤县| 延津县| 清镇市| 凤庆县| 拉孜县| 同仁县| 新民市| 和林格尔县| 内乡县| 嘉兴市| 宿州市| 宁国市| 本溪市| 融水| 团风县|