Native Rss Reader 的资料

来源:互联网 发布:php获取unix时间戳 编辑:程序博客网 时间:2024/06/05 21:03
转:http://hi.baidu.com/mikyliang/blog/item/11d420d3135832013af3cf19.html
RSS文档的构成
2007-05-04 14:58

RSS文档的构成:


一个RSS聚合由频道(channel)以及频道中包含的项目(item)组成
RSS遵从XML1.0标准进行标注
其头部一般应该是这样的:
<?xml version="1.0"?>          /*遵从的XML标准*/
<rss version="2.0">            /*遵从的RSS标准*/
<channel>                     /*频道标志*/

文件的结尾应该由下面的内容结束
</channel>
</rss>
在头部和尾部之间,就是RSS的内容了。RSS中
channel(频道)必须包含的元素是:
<title>              /*频道的题目*/
<link>               /*连接地址*/
<description>        /*对频道的描述*/
可选的参数包含:
<language>           /*语言比如UTF-8、GB2312*/
<copyright>          /*版权信息*/
<managingEditor>     /*主要的维护者EMAIL*/
<webMaster>          /*网站管理者的EMAIL*/
<pubDate>            /*出版日期*/
<lastBuildDate>      /*最后建立日期*/
<category>           /*内容*/
<generator>          /*生成器*/
<docs>               /*文档的连结地址*/
<cloud>              /*这个解释起来有点难,她是对xml-rpc(远程过程调用)和soap(简单对象访问协议)的描述信息,能够使客户端软件注意到RSS的文档更新,就是所谓“推”的技术吧,一个服务器(被称作"cloud")提供一个RSS文档的更新公告,当一个文档被更新,这个服务器呼叫所有订阅的客户机注意最新的更新。一个例子<cloud domain="rpc.sys.com" port="80" path="/RPC2" registerProcedure="myCloud.rssPleaseNotify" protocol="xml-rpc" />*/
<ttl>                   /*存活时间,这个频道被源刷新之前被缓存的时间*/
<image>                 /*图像*/
<rating>                /*图像的等级?速率,文档 中描述不是很清楚或我没有理解*/
<textInput>             /*一个输入框,主要用来提供一个搜索引擎或提供一个读者反馈的的输入框,但很多的聚合器会忽略它*/
<skipHours>            /*给聚合器的一个忽略时间提示,多长时间他们可以跳过*/
<skipDays>             /*给聚合器的一个忽略日期提示,多长时间他们可以跳过*/
在频道描述完毕后,接下来应该对rss聚合中的主要内容项目进行描述
一个项目有<item></item>包含其中的内容就是这个项目的信息
一个item项目必须包含下面这些元素
<title>                   /**/
<description>                   /**/
<link>                   /**/
可以选择的元素包括
<author>                   /*作者*/
<category>                   /*分类*/
<comments>                   /*注释*/
<enclosure>                   /*附件,(还可以包含一个多媒体附件呢),比如:<enclosure url="http://www.scripting.com/mp3s/weatherReportSuite.mp3" length="12216320" type="audio/mpeg" />*/
<guid>                   /*唯一描述符*/
<pubDate>                   /*出版时间*/

<source>                   /*源*/




http://dev.uphoneapp.com/doc/view.xhtml?id=52265

Rss Reader实例开发之Xml与RSS解析

Rss Reader实例开发之Xml与RSS解析


我们在《JSON格式解析和libjson使用简介》中介绍了JSON格式的解析,这里将介绍下一个更普遍使用的网络数据交换格式XML,及基于XML语言而扩展出来用于内容聚合的格式规范RSS,并结合实例介绍下XML/RSS的解析与生成。
 

XML简介: 

XML(Extensible Markup Language)即可扩展标记语言,它是由一系列的自定义的标签和数据组成,是被设计用来结构化、存储以及传输信息,在形式上与HTML很类似,最大的区别是XML的标签都是自定义的。XML标签是区分字母大小写的,所有的XML元素都必需有关闭标签,如:〈abc〉〈/abc〉或写成〈abc /〉。

XML 元素指的是从(且包括)开始标签直到(且包括)结束标签的部分。元素可包含其他元素(即子元素)、文本或者两者的混合物。元素也可以拥有属性,属性值须加引号,如attr=”XXX”,元素中每个属性间用空格分隔。

XML 文档由XML序言开始,XML序言是描述该文档的并有一个包含其他所有元素的父元素,该元素称为根元素/文档元素。

 
  1. <xml version="1.0"encoding="UTF-8"standalone="no"?>
  2. <root>  
  3.   <child1 subNum=”3”>  
  4.     <subchild1>1st text</subchild1>
  5.     <subchild2>2nd text</subchild2>
  6.     <subchild3>3rd text</subchild3>
  7.   </child1>
  8.   <child2>  
  9.     <subchild4>4th text</subchild4>
  10.   </child2>
  11. root>
 

〈root〉便是这XML文档的根元素,根元素下面有两了元素:〈child1〉与〈child2〉,而〈child1〉元素下面又有三个子元素〈subchild1〉、〈subchild2〉和〈subchild3〉,这三个元素下面不再有子元素了,都是包含了文本内容。〈child1〉还有一个subNum属性,其值是3。

可以看出XML是以一种树结构来组织数据的。每个元素便是一个节点,元素的子元素便是这个节点的子节点,元素的文本内容就是这棵树的叶子。所以上例可以用一棵树状结构来描述,请看下图:


 

在RssReader中使用XML:

在对XML有了一个基础认识,就可以在这基础上使用它,接下来就介绍一下如何在代码中解析和生成一份XML文档。网络上有很多优秀的解析/生成XML文档的开源库,如:libxml、TinyXML等,这里我们选择了TinyXML,主要是因为TinyXML对中文的支持比libxml好。TinyXML是一款简单小巧的C++ XML解析器,使用文档对象模型(DOM),不支持文档类型定义(DTDs)和可扩展样式表语言(XLSs)。

TinyXML支持两种方式的字符串处理,一种是使用STL的std::string类型及其流操作,一种是TinyXML自定义的String类型及操作。由于沃Phone平台使用的是android的编译器,而android的编译器是不支持STL的部分功能,如其流操作等,所以我们要在沃Phone平台上正常使用TinyXML,那么就要将tinyxml.h文件中的宏定义(TIXML_USE_STL)给注释掉,这样在编译时就会选择使用TinyXML自定义的String类型及操作。如下代码:

 
  1. //#define TIXML_USE_STL
  2. #ifdefTIXML_USE_STL
  3.     #include 〈string〉
  4.     #include 〈iostream〉
  5.     #include 〈sstream〉
  6.     #define TIXML_STRING std::string
  7. #else
  8.     #include"tinystr.h"
  9.     #defineTIXML_STRING TiXmlString
  10. #endif



如此修改之后,就可以在交叉编译时顺利通过了。

在TinyXML中有如下所列的类与上图中的各节点概念相对应:
1、TiXmlDocument:对应上图中的XML file节点,代表整份文档;
2、TiXmlDeclaration :对应上图中的XML序言节点,它表示文件的声明部分;
3、TiXmlComment :是一个注释类,它表示文件的注释部分;
4、TiXmlElement :对应上图中除XML序言节点外的所有白色椭圆节点(从root到subchild[n]),它是文件的主要部分,并且支持嵌套结构;
5、TiXmlAttribute/TiXmlAttributeSet :元素属性,它一般嵌套在元素中,用于记录此元素的一些属性,对应上图中的subNum的白色矩形框;
6、TiXmlText :对应上图中的绿色椭圆节点,文本对象,它嵌套在某个元素内部;

下面就介绍一下如何使用TinyXML来解析XML文档:
一切都是从TiXmlDocument对象开始的,也就是说要先new一个TiXmlDocument对象,再调用相应的Load方法将文档内容装载到TiXmlDocument对象中。而这个过程又可分成两种方式:
1、先创建一个空的TiXmlDocument对象,再调用LoadFile(“文档路径”)装载,如:

 
  1. TiXmlDocument* pTiXmlDoc =newTiXmlDocument();
  2. if(pTiXmlDoc)
  3. {
  4.       pTiXmlDoc->LoadFile (“test.xml”);
  5. }

2、在创建对象时就在构造函数中传入文档路径,再调用LoadFile()装载,如:

 
  1. TiXmlDocument* pTiXmlDoc =newTiXmlDocument(“test.xml”);
  2. if(pTiXmlDoc)
  3. {
  4.      pTiXmlDoc->LoadFile ();
  5. }

第一种方式中,又根据传入的参数类型与数量不同而分为下面3个API:

 
  1. bool LoadFile( TiXmlEncodingencoding= TIXML_DEFAULT_ENCODING);
  2. bool LoadFile(constchar* filename, TiXmlEncodingencoding = TIXML_DEFAULT_ENCODING);
  3. bool LoadFile( FILE*, TiXmlEncodingencoding= TIXML_DEFAULT_ENCODING);

在RssReader中对TinyXML扩展了三个API:

 
  1. bool LoadFileTG3( TiXmlEncodingencoding= TIXML_DEFAULT_ENCODING);
  2. bool LoadFileTG3( Handlefile, TiXmlEncodingencoding= TIXML_DEFAULT_ENCODING);
  3. bool LoadFileTG3( constTUChar* _filename, TiXmlEncodingencoding= TIXML_DEFAULT_ENCODING);


在装载数据成功后,我们就可以从这个DOM结构中提取我们关心的数据。首先先获取文档的根元素:
TiXmlElement* pTiXmlRootElem = pTiXmlDoc->RootElement();
TinyXML是基于树状结构的,所以我们需要通过TiXmlElement类的FirstChildElement(key)方法一级一级地获取下一级元素的指针,如:
TiXmlElement* pTiXmlElem = = pTiXmlRootElem->FirstChildElement("child1");
如果要获取child1节点的属性值subNum,则需要调用Attribute(key, value),其中value为[out]型参数,是把属性key对应的值放到value中,如:
    Int32 nValue = 0;
    pTiXmlElem->Attribute("subNum", &nValue);
而如果某个元素下面全部/部分子元素的key为一样的话(可以理解成数组),我们可以使用TiXmlElement指针及FirstChildElement(key)与NextSiblingElement(key)来遍历该元素的所有子元素,如:

 
  1. TiXmlElement* pCur = NULL;
  2. for (pCur = pTiXmlRootElem->FirstChildElement("item"); pCur; pCur = pCur->NextSiblingElement("item"))
  3. {
  4.          //TODO
  5. }

而最终获取元素的文本内容时,是使用GetText()方法。下面就举个RssReader中用于解析RSS文档中前面若干条新闻ITEM的一个例子:

 
  1. void TMainPageData::LoadDataFromXmlFile(TUChar* pszFilePath)
  2. {
  3.     TiXmlDocument* pTiXmlDoc = NULL;
  4.     TiXmlElement* pTiXmlRootElem = NULL;
  5.  
  6.     //创建一个TiXmlDocument对象
  7.     pTiXmlDoc = new TiXmlDocument();
  8.     if (pTiXmlDoc)
  9.     {
  10.         //装载pszFilePath文件中的数据
  11.         if (pTiXmlDoc->LoadFileTG3(pszFilePath))
  12.         {
  13.             //获取根元素
  14.             pTiXmlRootElem = pTiXmlDoc->RootElement();
  15.             if (pTiXmlRootElem && (pTiXmlRootElem = pTiXmlRootElem->FirstChildElement("channel")))
  16.             {
  17.                 char* pszEncoding ="utf-8";
  18.                 TiXmlElement* pTiXmlElem = NULL;
  19.                 TiXmlElement* pCur = NULL;
  20.  
  21.                 //遍历channel元素下的key 为“item”的元素
  22.                 for (pCur = pTiXmlRootElem->FirstChildElement("item"); pCur;
  23.                     pCur = pCur->NextSiblingElement("item"))
  24.                 {
  25.                     //只取MAIN_PAGE_SHOW_NEWS_NUM条item
  26.                     if (m_aHotNews.size() < MAIN_PAGE_SHOW_NEWS_NUM)
  27.                     {
  28.                         NewsItemData* pNewsItem = new NewsItemData;
  29.  
  30.                         //获取item的title
  31.                         pTiXmlElem = pCur->FirstChildElement("title");
  32.                         if (pTiXmlElem)
  33.                         {
  34.                             //将title值转成Unicode编码,并new一块内存用于存放该
  35.                             //Unicode编码的title
  36.                             pNewsItem->pszTitle = MakeNewCopy2Unicode(pTiXmlElem->GetText(), pszEncoding);
  37.                         }
  38.                         pTiXmlElem = pCur->FirstChildElement("link");
  39.                         if (pTiXmlElem)
  40.                         {
  41.                             pNewsItem->pszLink = MakeNewCopy(pTiXmlElem->GetText());
  42.                         }
  43.                         pTiXmlElem = pCur->FirstChildElement("pubDate");
  44.                         if (pTiXmlElem)
  45.                         {
  46.                             pNewsItem->pszTime = MakeNewCopy(pTiXmlElem->GetText());
  47.                         }
  48.                         pTiXmlElem = pCur->FirstChildElement("guid");
  49.                         if (pTiXmlElem)
  50.                         {
  51.                             pNewsItem->pszGuid = MakeNewCopy(pTiXmlElem->GetText());
  52.                         }
  53.                         pTiXmlElem = pCur->FirstChildElement("description");
  54.                         if (pTiXmlElem)
  55.                         {
  56.                             pNewsItem->pszDesc = MakeNewCopy(pTiXmlElem->GetText());
  57.                         }
  58.  
  59.                         m_aHotNews.push_back(pNewsItem);
  60.                     }
  61.                 }
  62.  
  63.                 pTiXmlRootElem = NULL;
  64.             }
  65.         }
  66.  
  67.         delete pTiXmlDoc;
  68.         pTiXmlDoc = NULL;
  69.     }
  70. }

上面这段代码是实现将指定文件路径的XML文档解析并提取其中部分数据,存放到m_aHotNews的vector变量中。
 
当然TinyXML还提供一种使用句柄提取数据的方式,不过这里就不作介绍,只是取个例子,如:

 
  1. TiXmlHandle docHandle( &document );
  2. TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild("Element" ).Child("Child", 1 ).ToElement();
  3. if ( child2 )
  4. {
  5.        //TODO
  6. }


使用TinyXML来生成并保存XML文档:
生成一棵XML树(文档),其中的诸多工作基本可以归纳为可递归的三个步骤:
1、创建/new一个节点对象;
2、设置节点对象的属性值;
3、建立节点与子节点间的连接;

最终将文档保存到本地时,只要调用SaveFileTG3("文档路径")方法。例子代码如下:

 
  1. TiXmlDocument* pTiXmlDoc = NULL;
  2. TiXmlElement* pTiXmlRootElem = NULL;
  3. TiXmlText* pTiXmlText = NULL;
  4.  
  5. pTiXmlDoc = new TiXmlDocument();
  6. if (pTiXmlDoc)
  7. {
  8.     //创建根节点
  9.     pTiXmlRootElem = new TiXmlElement("root");
  10.     if (pTiXmlRootElem)
  11.     {
  12.     //将根节点连接到TiXmlDocument对象中
  13.     pTiXmlDoc->LinkEndChild(pTiXmlRootElem);
  14.  
  15.     //创建child节点
  16.     TiXmlElement* pTiXmlElem = new TiXmlElement("child1");
  17.     if (pTiXmlElem)
  18.     {
  19.         //将child1节点连接到根节点root
  20.         pTiXmlRootElem->LinkEndChild(pTiXmlElem);
  21.  
  22.         //设置child1节点的属性subNum为3
  23.         pTiXmlElem->SetAttribute("subNum", 3);
  24.  
  25.         //创建叶子节点
  26.         pTiXmlText = new TiXmlText(“1st text”);
  27.         if (pTiXmlText)
  28.         {
  29.             //将叶子节点连接到child1节点上
  30.             pTiXmlElem->LinkEndChild(pTiXmlText);
  31.             pTiXmlText = NULL;
  32.         }
  33.         pTiXmlElem = NULL;
  34.     }
  35.  
  36.     pTiXmlRootElem = NULL;
  37.     }
  38.  
  39.     //将文档保存到本地
  40.     pTiXmlDoc->SaveFileTG3(m_szFileFullName);
  41.     delete pTiXmlDoc;
  42.     pTiXmlDoc = NULL;
  43. }

 

RSS简介:

RSS为Really Simple Syndication(简易供稿)的缩写,也叫聚合内容,通常在时效性比较强的内容上使用RSS订阅能更快速获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新。RSS,原意是把网站内容如标题、链接、部分内文甚至全文转换为可延伸标示语言(XML:eXtensible Markup Language)的格式,以向其它网站供稿。

其实RSS文档就是一份有自身规范的XML文档,通用的RSS文档格式如下:

 

  1. xml version="1.0"?>
  2.  

  3. <rss version="2.0">
  4.  

  5. <channel>
  6.     
  7.     
  8.     <title>Lift Off Newstitle>
  9.  
  10.     
  11.     <link>http://liftoff.msfc.nasa.gov/link>
  12.  
  13.     
  14.     <description>Liftoff to Space Exploration.description>
  15.  
  16.     
  17.     <language>en-uslanguage>
  18.  
  19.     
  20.     <pubDate>Tue, 10 Jun 2003 04:00:00 GMTpubDate>
  21.  
  22.     
  23.     <lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMTlastBuildDate>
  24.  
  25.     <docs>http://blogs.law.harvard.edu/tech/rssdocs>
  26.  
  27.     
  28.     <generator>Weblog Editor 2.0generator>
  29.     <managingEditor>editor@example.commanagingEditor>
  30.     <webMaster>webmaster@example.comwebMaster>
  31.  
  32.     
  33.     <ttl>5ttl>
  34.     
  35.  
  36.  
  37.     
  38.     <item>
  39.         
  40.         <title>Star Citytitle>
  41.  
  42.         
  43.         <link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asplink>
  44.  
  45.         
  46.         <description>How do Americans get ready to work with Russians aboard theInternational Space Station? They take a crash course in culture, languageand protocol at Russia's Star City.description>
  47.  
  48.         
  49.         <pubDate>Tue, 03 Jun 2003 09:39:21 GMTpubDate>
  50.  
  51.         
  52.         <category>ITcategory>
  53.  
  54.         
  55.         <author>bill@xxx.comauthor>
  56.  
  57.         
  58.         <guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573guid>
  59.  
  60.         
  61.         <comments>http://news.mtc.sohu.com/news/channel/1/news/13604.html#commentscomments>
  62.  
  63.         
  64.         <source>source>
  65.  
  66.         
  67.         <enclosure>enclosure>
  68.     item>
  69.  
  70.     <item>
  71.         <title>Space Explorationtitle>
  72.         <link>http://liftoff.msfc.nasa.gov/link>
  73.         <description>Sky watchers in Europe, Asia, and parts of Alaska and Canadawill experience a partial eclipse of the Sun on Saturday, May 31st.description>Fri, 30 May 2003 11:06:42 GMTpubDate>
  74.         <guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572guid>
  75.     item>
  76.  
  77.     <item>
  78.         <title>The Engine That Does Moretitle>
  79.         <link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asplink>
  80.         <description>Before man travels to Mars, NASA hopes to design new enginesthat will let us fly through the Solar System more quickly. The proposedVASIMR engine would do that.description>Tue, 27 May 2003 08:37:32 GMTpubDate>
  81.         <guid>http://www.zhanghangfeng.cn/rss.xmlguid>
  82.     item>
  83.  
  84.     <item>
  85.         <title>Astronauts' Dirty Laundrytitle>
  86.         <link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asplink>
  87.         <description>Compared to earlier spacecraft, the International SpaceStation has many luxuries, but laundry facilities are not one of them.Instead, astronauts have other options.description>Tue, 20 May 2003 08:56:02 GMTpubDate>
  88.         <guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570guid>
  89.     item>
  90.  
  91. channel>
  92. rss>

〈channel 〉及其子项〈item〉都有三项是一般拥有的元素:〈title〉、〈link〉和〈 description 〉,其它为可选。这只是一份一般情况下通用的格式,不同版本或不同的用途的RSS源的RSS格式会有所不一样,如:有的〈channel 〉下会有〈image〉、〈TextInput〉等标签,当然,我们也可按着RSS规范的精神来扩展一些功能,如在每个〈item〉中增加一项〈icon〉用来设定item的图标链接。
 

开源库MRss的使用:

在RSSReader项目中,用于解析/保存RSS格式的工具是mRss,mRss是一款开源库,现在官网上其最新版本是libmrss-0.9,它同时支持解析0.91、0.92、1.0和2.0四个版本的RSS格式。由于网络上下载的libmrss都是.c或.h为后缀的文件,而RSSReader项目中的C文件都是以.cpp为后缀的,所以我们在将libmrss里的C文件添加到项目中之前,要先把.c后缀改成.cpp。另外,我们还需要将源文件中的头部的宏定义给删/注释掉,删除的代码部分如下:

 
  1. #ifdef HAVE_CONFIG_H
  2.     #include
  3. #else
  4.     # error Use configure; make; make install
  5. #endif

在做完以上两步工作,libmrss就可以在我们的RSSReader项目中编译通过了。不过这时的mrss在解析带中文的RSS格式还是有很多问题的,因为RSS是基于XML格式的,所以MRSS解析RSS文档时的做法是:先将RSS文档解析到DOM中,再从DOM中提取数据放到MRSS自定义的结构体中,MRSS在解析和生成RSS文档的逻辑过程如下图:

而mrss是使用libxml来解析XML的,而libxml对中文的支持问题很大,特别是GB编码的中文,所以我们需要对mrss中执行解析工作的文件mrss_parser.cpp大刀阔斧地修改一番,全部改成使用TinyXML来解析XML,这样就可以很好的支持中文了。至于具体如何修改,这里就不赘述了,已有修改后的源码(RSSReader/mrss)上传到社区,请自行下载使用。

对应RSS文档的格式,在mrss中声明了如下几个主要的结构体类型来组织和存储RSS中的数据:

 
  1. typedef struct mrss_t mrss_t;
  2. typedef struct mrss_item_t mrss_item_t;
  3. typedef struct mrss_category_t mrss_category_t;
  4. typedef struct mrss_hour_t mrss_hour_t;
  5. typedef struct mrss_day_t mrss_day_t;

mrss_item_t、mrss_category_t、mrss_hour_t和mrss_day_t结构体类型都是链表结构,mrss_t是存放整个RSS文档数据的结构体类型,记录RSS的版本号、编码、标题等信息,以及指向mrss_item_t、mrss_category_t、mrss_hour_t和mrss_day_t结构体类型的链表的指针。其组织结构图如下:

mrss提供了丰富的API用于解析、保存、释放RSS数据等操作,
1、解析API,根据不同的数据源,分别提供了三种接口:
mrss_error_t     mrss_parse_url(char* url, mrss_t ** mrss);//用于解析网络上的RSS源
mrss_error_t     mrss_parse_file(char * file, mrss_t ** mrss);//用于解析本地文件
mrss_error_t     mrss_parse_buffer(char *buffer, size_t size_buffer, mrss_t ** mrss);//用于解析内存中的RSS数据
2、保存API:
mrss_error_t     mrss_write_file (mrss_t * mrss, char * file);//保存到本地文件
mrss_error_t     mrss_write_buffer  (mrss_t *mrss, char **  buffer);//保存到内存
3、释放API:
mrss_error_t     mrss_free (mrss_generic_t     element);//释放内存
除了上述API,还有一些其它用途的API,如编辑功能的API等。

解析RSS的例子:

 
  1. mrss_t* m_pRss = new mrss_t;
  2. if(m_pRss)
  3. {
  4.     MemSet(m_pRss, 0, sizeof(mrss_t));
  5.     // 解析rss的xml文件
  6.     if (MRSS_OK == mrss_parse_file(pszRssFilePath, & m_pRss))
  7.     {
  8.         mrss_item_t *pRssItem;
  9.         pRssItem = m_pRss->item;
  10.  
  11.         //TODO:
  12.         //……
  13.     }
  14.  
  15.     //作用结束后,要释放
  16.     mrss_free(m_pRss);
  17.     delete m_pRss;
  18.     m_pRss = NULL;
  19. }

 

总结:  

与JSON相比,一般情况下,传输相同信息量,使用XML格式比使用JSON格式产生的数据量大些。另外,在解析或生成XML格式文档也会比解析或生成JSON格式文档来的复杂一些。但是,XML格式的首尾标签对齐的形式,使其可读性和可编辑性会比JSON良好,所以XML常会用于需要人工阅读或编辑的情况下的数据存储和交换。



原创粉丝点击