需求

上一章我们解析完了upnp协议中的http头部获取了xml文件的地址,使用http协议我们再次获取xml文件后需要解析xml,我们最害怕的就是引入一个又一个库,事实上,libupnp就引入了很多库,造成了程序臃肿,打印频繁,我们使用c语言的strstr和sscanf来手动解析xml,获取特定字符串。

1、分解url

upnp协议中的LOCATION是从http头部获取而来,要知道如何获取,请看这一片文章

解析http头部
接下来就是使用sscanf函数来获取http 的host 端口和路由信息,如
http://192.168.1.144:1551/description.xml
我们要分解成为 http://192.168.1.144:1551/ 和路由 /description,使用一个非常绚丽的技巧,如下所示:

 const char *pos = ss["LOCATION"].c_str();//const char *url = "http://192.168.1.144:1551/description.xml";char http[256] = {"http://" };char route[256] = { 0 };if (*(pos + 4) == ':')pos += 7;sscanf(pos, "%[^/]%s", &http[7],route);

以上先把http://填入缓冲中,然后让sscanf 中缓冲的指针指向第7个字节,开始往里放解析值,sscanf函数跳过http://,找到我们字符串的下一个"/"位置。 ok,我们使用http协议下载xml文件,下载结束,得到xml body

1、下载下来后xml body

我们使用http协议在程序中拿到了xml body体

<?xml version ="1.0"?>
<root xmlns = "urn:schemas-upnp-org:device-1-0" xmlns:dlna = "urn:schemas-dlna-org:device-1-0">
<specVersion>
<major>1</major >
<minor>0</minor >
</specVersion>
<device>
<UDN>uuid:bb5e-21ce-1111-11b2-f918-ec9c-3235-709a-</UDN>
<friendlyName>Living Room 1_5336_HiDMR</friendlyName>
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType >
<manufacturer>Hisilicon Technologies Co., Ltd</manufacturer>
<manufacturerURL>http://www.Hisilicon.com</manufacturerURL><modelName>Hisilicon MediaRenderer</modelName><modelNumber>1.1</modelNumber><modelURL>http://www.Hisilicon.com</modelURL><serialNumber></serialNumber><dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC><dlna:X_DLNACAP xmlns:dlna="urn:schemas-dlna-org:device-1-0"></dlna:X_DLNACAP><serviceList><service><serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType ><serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>//需要获得下面这个controlURL<controlURL>/upnp/service/ConnectionManager/Control</controlURL><eventSubURL>/upnp/service/ConnectionManager/Event</eventSubURL><SCPDURL>/upnp/service/cms.xml</SCPDURL></service><service><serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType ><serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>//需要获得下面这个controlURL<controlURL>/upnp/service/AVTransport/Control</controlURL><eventSubURL>/upnp/service/AVTransport/Event</eventSubURL><SCPDURL>/upnp/service/avt.xml</SCPDURL></service><service><serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType ><serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>//需要获得下面这个controlURL<controlURL>/upnp/service/RenderingControl/Control</controlURL><eventSubURL>/upnp/service/RenderingControl/Event</eventSubURL><SCPDURL>/upnp/service/rcs.xml< / SCPDURL></service></serviceList></device></root>

这是一份upnp协议中的设备xml 描述,里面包含了几个关键信息,需要我们获取 我们需要的是:

1 设备名称
2 AVTransport 传输点的控制url
3 RenderingControl 点的控制url

熟悉upnp协议的同志们知道这个非常关键,下面我们来制定解决方案

2、定义数据结构

typedef struct s_xmlanalyse_c
{char friendlyName[64];char url_AVTransport[256];char url_RenderingControl[256];char url_ConnectionManager[256];
}s_xmlanalyse_c;

定义得到单个节点的内容函数,使用strstr函数来得到xml 字符串中的位置,将字符串内容使用memcpy来复制,字符串的本质是可打印并且最后一个字符是’\0’,因此我们使用memcpy 和 '\0’来生成新的字符串。


const char *GetValueOf_c(const char *sbody, const char *name, char *ret,int retlen)
{if (strlen(name) > 63)return NULL;char buf_fn1[64];char buf_fn2[64];sprintf(buf_fn1, "<%s>", name);sprintf(buf_fn2, "</%s>", name);const char *start = sbody;const char *end = sbody + strlen(sbody);char *fn =  &buf_fn1[0];char *fnn = &buf_fn2[0];int len = strlen(fn);const char * x1 = strstr(start, fn);const char * x2 = strstr(start + len,fnn);if (x1 != NULL && x2 != NULL){x1 += len;int len2 = (int)(x2 - x1);if (len2 > retlen - 1)return NULL;memcpy(ret, x1, x2 - x1);ret[x2 - x1] = '\0';return x2 + len+1;}return NULL;
}

获取三个节点内容

使用三个循环获取内容


int GetValueOf_Service_c(const char *fpos, s_xmlanalyse_c *value)
{const char * fname  = "serviceType";const char * fname2 = "controlURL";int flag = 0;char tmp[256];for (int i = 0; i < 3; i++){fpos = GetValueOf_c(fpos, fname, tmp,256);if (fpos == NULL){cout << "not good,xml is error" << endl;return -1;}if (strstr(tmp,"ConnectionManager") != NULL){fpos = GetValueOf_c(fpos, fname2, value->url_ConnectionManager,sizeof(value->url_ConnectionManager));flag++;}else if (strstr(tmp,"AVTransport") != NULL){fpos = GetValueOf_c(fpos, fname2, value->url_AVTransport,sizeof(value->url_AVTransport));flag++;}else if (strstr(tmp,"RenderingControl") != NULL){fpos = GetValueOf_c(fpos, fname2, value->url_RenderingControl,sizeof(value->url_RenderingControl));flag++;}}if (flag == 3)return 0;return -1;
}

总结

我们使用分解分而治之对待软件工程的方式,首先
A 定义数据结构
B 得到流程 --》2.1 http 头部分解–》2.2 分解url --》2.3获取xml --》2.4获取节点内容
C 定义截取url函数
其中2.4 分解为如下步骤
D 定义获取节点内容的函数
E 定义 调用4 函数得到多个节点内容的函数

c函数strstr和sscanf组合高级技巧相关推荐

  1. C 函数 strstr 的高效实现

          C函数库中有一个函数 strstr(char*, char*),它实现的是在一个原字符串中查找一个子串,如果找到这样的一个子串,返回这个子串在原字符串中的起始位置,若没有找到这样的一个子串 ...

  2. C语言学习笔记---字符串查找函数strstr()和strpbrk()函数

    strstr()函数   C语言中如何向查找一个字符串中是否包含另一个字符串,可以使用strstr()函数.使用示例如下: int main(int argc, char *argv[]) {char ...

  3. R语言ggplot2可视化:patchwork包将一个ggplot2可视化结果和一个plot函数可视化结果横向组合起来形成最终结果图、两个可视化的组合结果对齐、并为组合图像的每个子图添加标题

    R语言ggplot2可视化:使用patchwork包(直接使用加号+)将一个ggplot2可视化结果和一个plot函数可视化结果横向组合起来形成最终结果图.将两个可视化的组合结果对齐.并为组合图像的每 ...

  4. R语言拟合ARIMA模型:使用forecast包中的auto.arima函数自动搜索最佳参数组合、模型阶数(p,d,q)、设置seasonal参数指定在模型中是否包含季节信息

    R语言拟合ARIMA模型:使用forecast包中的auto.arima函数自动搜索最佳参数组合.模型阶数(p,d,q).设置seasonal参数指定在模型中是否包含季节信息 目录

  5. 如何用C语言实现各种字符函数和字符串函数strstr、memcpy、memmove、strlen、strcpy、strcmp、strcat

    用C语言模拟实现字符函数与字符串函数 strstr.memcpy.memmove.strlen.strcpy.strcmp.strcat 若使用本文相关代码,还请动手点个赞!!! #define _C ...

  6. c函数sscanf的高级技巧(二)

    第一篇文章 c函数sscanf高级技巧 需求 解析特定json,而不引入特定的库,如字符串 json字符串1"{\"ip\": [\"http://192.16 ...

  7. c函数sscanf的高级技巧

    在解析url过程中,有时需要非常简单的分解,这时候可以使用几种方法 例如 const char *url = "http://192.168.1.144:1551/AVTransport/c ...

  8. c语言函数库学习~sscanf~格式化输入

    ---恢复内容开始--- 今天算是被打击到了吧,由郑轻的acm老师来我学院指导安排了个现场的小比赛,,俺们居然有还是输给一个大一的新手,,哎,情何以堪,,所以还是要重视下基础编程能力的培训,现在嘛我就 ...

  9. linux c 字符串查找函数 strstr strcasestr

    一.strstr函数使用 [1] 函数原型 char *strstr(const char *haystack, const char *needle); [2] 头文件 #include <s ...

最新文章

  1. Reddit票选 | 2019年绝对不能错过的机器学习论文
  2. java异常_聊聊Java中的异常及处理
  3. 【腾讯第二届校园编程马拉松】HDU-4525,威威猫系列故事——吃鸡腿
  4. 配置HDFS HttpFS和WebHDFS
  5. 省选+NOI 第六部分 技巧与思想
  6. 江苏通报“中通宠物盲盒”事件:已立案调查
  7. cn.cw.gps.domain.VisitReport.setVisitID([Ljava.lang.String;)]
  8. Python并行实例
  9. mysql 索引越界_mysql隐式转换造成索引失效的事故总结
  10. namesilo续费
  11. ABAP BDC个人使用见解
  12. 用C语言写一个简单的飞机大战游戏(用到easyx图形库)
  13. 中国计量大学现代科技学院第四届“中竞杯”程序设计校赛(同步赛)F.爬塔
  14. 对矩阵乘法本质的理解——从向量线性组合角度
  15. 【综合笔试题】难度 3/5,挺有意思的一道题(既可图论,也可贪心)
  16. CleanMyMac2023Mac下载排行最好的清理工具
  17. 高电压放大器与高电流放大器该如何选择使用
  18. 心跳异常检测--使用Keras,K折交叉训练CNN一维卷积
  19. Flash按键响应-键码值表
  20. linux pwm控制蜂鸣器 滴滴_第七章----pwm蜂鸣器

热门文章

  1. 一图看懂cortex-M0/M3矢量表,记住LSB置1表示Thumb
  2. 五十步笑百步翻译软件测试,五十步笑百步
  3. Google十大真理带给中国网络公司的启示
  4. B站回应视频监控被破解上传:下架相关内容 封禁账号
  5. 极兔正式入股百世快递
  6. 爱回收回应下架通报:认真整改 切实落实用户隐私信息保护
  7. 被低估的“败家爷们”
  8. 蛋壳租客迎来好消息!微众银行开放贷款结清入口
  9. iPhone 12开启5G续航锐减 苹果官方回应了!
  10. 巴菲特:承认错误“抄底”航空股,不看好航空公司