接上文,上文中提到获取网络直播电视地址的方法,但是大量信息需要人工的方式进行处理,过于麻烦。所以本文针对三级的XML解析和下载工作进行处理。
技术点:1、利用tinyXML完成XML的解析工作 tinyxml下载
2、利用libcurl完成xml的下载工作 libcurl下载
公用下载函数:
// 下载相关的XML static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) { size_t nsize=size*nmemb; //…在这里保存数据 string *strHtml=(string*)userp; strHtml->append((char*)buffer,nsize); return nsize; } bool downloadXml(const char* fileUrl, string& xmlStr) { if ("" == fileUrl) { dxreport("downloadXml: fileUrl is empty ..."); return false; } xmlStr = ""; // 清空缓存XML CURL* m_curl = curl_easy_init(); if (NULL == m_curl) { dxreport("downloadXml: create curl fail ..."); return false; } string* str = new string(); curl_easy_reset(m_curl); //主要是在重复调用GET/POST时,清空curl中的设置 curl_easy_setopt(m_curl, CURLOPT_URL, fileUrl); curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA,(void *)str); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data); CURLcode res = curl_easy_perform(m_curl); curl_easy_cleanup(m_curl); if (res != CURLE_OK || str->length() == 0) { dxreport("downloadXml: download xml fail! url = %s", fileUrl); cout << fileUrl << endl; return false; } xmlStr = *str; return true; }
解析第一级XML:
<?xml version="1.0" encoding="UTF-8"?> <atv> <body> <listScrollerSplit id="com.sample.list-scroller-split"> <header> <simpleHeader> <title>电视直播</title> </simpleHeader> </header> <menu> <sections> <menuSection> <header> <textDivider alignment="left"> <title>类别选择</title> </textDivider> </header> <items> <oneLineMenuItem id="list_1"> <label>央视直播</label> <preview> <link>http://atv.jianguoke.com/appletv/tv/list_1.xml</link> </preview> </oneLineMenuItem> </items> </menuSection> </sections> </menu> </listScrollerSplit> </body> </atv>
样例XML如上所示,现在我们开始解析工作。
// 解析第一级XML bool parseFristXml(const char* fileName, list<CHANNEL_INFO>& listChannel) { string strXml = ""; if (false == downloadXml(fileName, strXml)) { return false; } TiXmlDocument* document = new TiXmlDocument(); if (false == document->Parse(strXml.c_str())) { return false; } /*TiXmlDeclaration *decl; decl = document->FirstChild()->ToDeclaration();*/ // 查找到根部 TiXmlElement* rootElement = document->RootElement(); TiXmlElement* keyBody = rootElement->FirstChildElement(); TiXmlElement* keyListScrollerSplit = keyBody->FirstChildElement(); TiXmlElement* keyHeadFrist = keyListScrollerSplit->FirstChildElement(); TiXmlElement* keyMenu = keyHeadFrist->NextSiblingElement(); if (keyMenu == NULL) { return false; } // 进入到menu中 TiXmlElement* keySections = keyMenu->FirstChildElement(); TiXmlElement* keySectionsMenu = keySections->FirstChildElement(); TiXmlElement* keySectionsHeaderMenu = keySectionsMenu->FirstChildElement(); TiXmlElement* keySectionsItems = keySectionsHeaderMenu->NextSiblingElement(); // 发现解析头部 TiXmlElement* item = keySectionsItems->FirstChildElement(); // 取得第一个标签 while (item) { CHANNEL_INFO info; TiXmlElement* oneLineMenuItem = item->FirstChildElement(); // 获取lable的内容 info.name = changeTxtEncoding(oneLineMenuItem->GetText()); oneLineMenuItem = oneLineMenuItem->NextSiblingElement()->FirstChildElement(); info.fileUrl = oneLineMenuItem->GetText(); listChannel.push_back(info); // 存储数据 item = item->NextSiblingElement(); // 切到下个标记 } return true; }
tinyXML函数的具体使用在这里就不累赘了,针对TinyXML解析方法可参见博客的其他相关内容。
解析第二级XML:
<?xml version="1.0" encoding="UTF-8"?> <atv> <head> <script src="http://atv.jianguoke.com/appletv/video.js"/> </head> <body> <preview> <scrollerPreview id="com.sample.scrollerPreview"> <items> <grid id="grid_1" columnCount="5"> <items> <sixteenByNinePoster id="type1_1" alwaysShowTitles="true" accessibilityLabel="" onHoldSelect="savevideofav('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/img/m_cctv1.png', 'CCTV-1 综合', '5')" onSelect="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'CCTV-1 综合', '5')" onPlay="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'CCTV-1 综合', '5')"> <title>CCTV-1 综合</title> <image>http://atv.jianguoke.com/appletv/tv/img/m_cctv1.png</image> <defaultImage>resource://Poster.png</defaultImage> </sixteenByNinePoster> <sixteenByNinePoster id="type1_2" alwaysShowTitles="true" accessibilityLabel="" onHoldSelect="savevideofav('http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'http://atv.jianguoke.com/appletv/tv/img/m_cctv2.png', 'CCTV-2 财经', '5')" onSelect="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'CCTV-2 财经', '5')" onPlay="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'CCTV-2 财经', '5')"> <title>CCTV-2 财经</title> <image>http://atv.jianguoke.com/appletv/tv/img/m_cctv2.png</image> <defaultImage>resource://Poster.png</defaultImage> </sixteenByNinePoster> </items> </grid> </items> </scrollerPreview> </preview> </body> </atv>
处理函数为:
// 解析第二级XML bool parseSecondXml(list<CHANNEL_INFO> fristXmlChannel, list<CHANNEL_INFO>& secondXmlChannel) { int len = fristXmlChannel.size(); if (len == 0) { dxreport("parseSecondXml: get fristXmlChannel is empty!"); return false; } for (int i = 0; i < len; i++) { CHANNEL_INFO info; list<CHANNEL_INFO>::iterator iter = fristXmlChannel.begin(); info = (*iter); fristXmlChannel.pop_front(); // 清除头部的数据 string strXml = ""; if (false == downloadXml(info.fileUrl.c_str(), strXml)) { continue; } // 进行二级解析XML TiXmlDocument* document = new TiXmlDocument(); if (false == document->Parse(strXml.c_str())) { return false; } TiXmlElement* element = document->RootElement(); element = element->FirstChildElement(); element = element->NextSiblingElement(); // body for (int i = 0; i < 6; i++) { element = element->FirstChildElement(); } // 获取三级XML下载地址 while (element) { TiXmlAttribute* attribute = element->FirstAttribute(); while (attribute) { string keyName = attribute->Name(); if (keyName == "onPlay") { // 获取到的内容如下格式: //"playvideo('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'CCTV-1 综合', '5')" string strContent = attribute->Value(); // 解析字符串 int len = strContent.length(); string keyStr[4] = {"", "", "", ""}; string str = ""; int keyNum = 0; for (int i = 0; i < len; i ++) { if (strContent[i] == '\'') { if (strContent[i+1] == ',') { keyStr[keyNum] = str; keyNum ++; } str = ""; continue; } str += strContent[i]; } // 存储数据 CHANNEL_INFO newInfo; newInfo.fileUrl = keyStr[0]; newInfo.name = changeTxtEncoding(keyStr[2].c_str()); secondXmlChannel.push_back(newInfo); } attribute = attribute->Next(); } element = element->NextSiblingElement(); } } return true; }
解析第三级XML:
<?xml version="1.0" encoding="UTF-8"?> <atv> <body> <videoPlayer id="com.sample.video-player"> <httpFileVideoAsset id="live_3_5"> <mediaURL>http://182.140.144.32:8080/playlist/37.m3u8?key=rkH0PG-pfffEkcMUDSZoEwbswucCuObIj1fYeg..</mediaURL> <title/> <description/> <image/> </httpFileVideoAsset> </videoPlayer> </body> </atv>
解析函数:
// 解析最后一级XML bool parseEndXml(list<CHANNEL_INFO> secondXmlChannel, list<CHANNEL_INFO>& endXmlChannel) { int len = secondXmlChannel.size(); if (len == 0) { dxreport("parseSecondXml: get fristXmlChannel is empty!"); return false; } for (int i = 0; i < len; i++) { CHANNEL_INFO info; list<CHANNEL_INFO>::iterator iter = secondXmlChannel.begin(); info = (*iter); secondXmlChannel.pop_front(); // 清除头部的数据 string strXml = ""; if (false == downloadXml(info.fileUrl.c_str(), strXml)) { continue; } // 进行三级级解析XML TiXmlDocument* document = new TiXmlDocument(); if (false == document->Parse(strXml.c_str())) { return false; } TiXmlElement* element = document->RootElement(); for (int i = 0; i < 4; i++) { element = element->FirstChildElement(); } CHANNEL_INFO newInfo; newInfo.fileUrl = element->GetText(); newInfo.name = info.name; endXmlChannel.push_back(newInfo); cout << newInfo.name << ":" << newInfo.fileUrl << endl; } return true; }
以上就是相关处理内容。望给各位有所帮助 ....