使用CJSON库实现XML与JSON格式的相互转化
之前完成了一个两个平台对接的项目。由于这两个平台一个是使用json格式的数据,一个是使用xml格式的数据,要实现它们二者的对接就涉及到这两个数据格式的转化,在查阅相关资料的时候发现了这个CJSON库,cjson是使用c编写的,它轻巧易用,在网上查了相关的资料后决定在json格式的存储于解析这块采用cjson库,而xml就简单的来解析字符串。
cjson库中常用的几个函数简介
cJSON_Parse
该函数需要传入一个json格式的字符串,函数会将这个字符串转化为json格式保存起来,函数会返回一个表示json对象的指针,如果传入json格式字符串有误,函数会返回NULL,所以在之后如果要使用它生成的json对象的指针,一定要校验指针值
cJSON_CreateObject
创建一个json格式的对相关,用来保存之后的json格式数据
cJSON_CreateArray
创建一个json格式的数组
cJSON_AddItemToObject
将某个数据插入到对应的json对象中,函数需要三个参数,第一个参数是一个json对象,表示要往哪个json对象里面插入数据,第二个参数是一个字符串指针,表示该项的键值,第三个参数是一个json对象,表示要将何种对象插入到json对象中,这个函数一般是用来插入一个数组对象
cJSON_AddNumberToObject
对于插入数值,或者字符串值,如果调用cJSON_AddItemToObject,需要向将他们转化为json对象然后插入,为了方便库中提供了一个宏来方便插入数字值,它的参数与cJSON_AddItemToObject类似,只是最后一个参数是一个数字值
cJSON_AddStringToObject
将字符串插入json对象中,它的用法与cJSON_AddNumberToObject相同
cJSON_Print
将json对象转化为json格式的字符串
cJson_Delete
由于cjson对象是用malloc函数分配的内存,所以需要使用这个函数来释放分配的内存,否则会造成内存泄露。这个函数会释放对象中的所有内存单元,包括使用相关函数添加到对象中的子对象,所以在释放了对象的内存后,它的子对象的内存就不需要再次释放了
cJosn结构体
typedef struct cJSON
{
struct cJSON *next;
struct cJSON *prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
} cJSON;
cjson中采用该结构体来存储json格式的数据,这个结构体存储的是json格式的单个项,其中为了能存储所有常用类型的数据,在里面定义了三种类型的成员,分别表示不同的数据类型值,string 成员表示的是该项的键值;它里面的三个指针分别表示同级别的下一项,上一项以及它的子节点,这些值在遍历这个json对象中的数据时需要用到
具体的算法
json格式转化为xml格式
string CJson::Json2Xml(const string &strJson)
{
string strXml = "";
cJSON *pRoot = cJSON_Parse(strJson.c_str());
if (NULL == pRoot)
{
return "";
}
cJSON *pChild = pRoot->child;
while (pChild != NULL)
{
if (pChild->child != NULL) //存在子节点的情况
{
std::string strSubKey = pChild->string; //获取它的键
std::string strSubValue = Json2Xml(cJSON_Print(pChild)); //获取它的值
std::string strSubXml = "<" + strSubKey + ">" + strSubValue + "</" + strSubKey + ">";
strXml += strSubXml;
}else
{
std::string strKey = pChild->string;
std::string strVal = "";
if (pChild->valuestring != NULL)
{
string strTemp = pChild->valuestring;
strVal = "\"" + strTemp + "\"";
}else
{
//其余情况作为整数处理
strVal = cJSON_Print(pChild);
}
strXml = strXml + "<" + strKey + ">" + strVal + "</" + strKey + ">";
}
pChild = pChild->next;
}
if(NULL != pRoot)
{
cJson_Delete(pRoot);
}
return strXml;
}
上述代码首先将传进来的json格式的字符串转化为json对象,然后再遍历这个json对象。cjson在存储json格式的数据时,首先利用一个空的cJson结构体来保存整个json格式,类似于存在头指针的链表,它的child节点指针指向的是里面的第一个成员的信息,所以在遍历之前需要将指针偏移到它的child节点处。这个遍历的整体思想是:依次遍历它的同级节点,分别取出它的键和值key、value,并且将这一项组织成类似于
<key>value</key>
它的同级节点以相同的字符串结构添加到它的后面。如果某个成员中有子节点,那么递归调用这个函数,,并将返回的值作为value,在它的两侧加上key的标签。另外在遍历的时候需要注意的是它的值,其实这块可以使用cjson结构中的type来做更精准的判断,之前我在写这块的代码的时候没有仔细的查看库的源代码,所以简单的利用valuestring指针来判断,如果是字符串那么在字符串的两侧加上引号,否则什么都不加,在生成的xml中只需要判断值中是否有引号,有则表示它是一个字符串,否则是一个数字类型的值
xml转json
//暂时不考虑xml标签中存在属性值的问题
string CJson::Xml2Json(const string &strxml)
{
cJSON *pJsonRoot = cJSON_CreateObject();
string strNext = strxml;
int nPos = 0;
while ((nPos = strNext.find("<")) != -1)
{
string strKey = GetXmlKey(strNext);
string strValue = GetXmlValueFromKey(strNext, strKey);
string strCurrXml = strNext;
strNext = GoToNextItem(strNext, strKey);
int LabelPos = strValue.find("<"); // < 所在位置
int nMarkPos = strValue.find("\""); // " 所在位置
if (strValue != "" && LabelPos != -1 && LabelPos < nMarkPos) //引号出现在标签之后
{
//里面还有标签
string strNextKey = GetXmlKey(strNext);
//下一个的标签与这个相同,则为一个数组
if (strNextKey == strKey)
{
cJSON *pArrayObj = cJSON_CreateArray();
int nCnt = GetArrayItem(strCurrXml);
for (int i = 0; i < nCnt; i++)
{
strKey = GetXmlKey(strCurrXml);
strValue = GetXmlValueFromKey(strCurrXml, strKey);
string strArrayItem = Xml2Json(strValue);
cJSON *pArrayItem = cJSON_Parse(strArrayItem.c_str());
cJSON_AddItemToArray(pArrayObj, pArrayItem);
strCurrXml = GoToNextItem(strCurrXml, strKey);
}
cJSON_AddItemToObject(pJsonRoot, strNextKey.c_str(), pArrayObj);
strNext = strCurrXml;
}else
{
//否则为普通对象
string strSubJson = Xml2Json(strValue);
cJSON *pSubJsonItem = cJSON_CreateObject();
pSubJsonItem = cJSON_Parse(strSubJson.c_str());
cJSON_AddItemToObject(pJsonRoot, strKey.c_str(), pSubJsonItem);
}
}
else
{
if (strValue.find("\"") == -1) //这个是数字
{
cJSON_AddNumberToObject(pJsonRoot, strKey.c_str(), atof(strValue.c_str()));
}else
{
remove_char(strValue, '\"');
cJSON_AddStringToObject(pJsonRoot, strKey.c_str(), strValue.c_str());
}
}
}
string strJson = cJSON_Print(pJsonRoot);
cJson_Delete(pJsonRoot);
return strJson;
}
就像注释上说的,这段代码没有考虑xml中标签存在属性的问题,如果考虑上的话,我的想法是将属性作为该项的子项,给子项对应的键名做一个约定,以某个规律来命名,比如”标签名_contrib”,这样在解析的时候一旦出现后面带有contrib的字符样式,就知道它是属性,后面就遍历这个子节点取出并以字符串的形式保存即可
算法的思想跟之前的类似,在这我定义了几个函数用来从xml中取出每一项的键,值信息,然后将这些信息保存到json对象中,最后生成一个完整的json对象,调用print函数将对象转化为json格式的字符串。
在while表示如果它的后面没有”<”表示后面就没有对应的值,这个时候就是xml格式的数据遍历完了,这个时候结循环中判断了下是否存在下一个标签,如果没有则结束循环,返回json格式字符串,函数返回。
在循环中依次遍历它的每一个标签,在第一个if判断中出现这样的语句strValue != “” && LabelPos != -1 && LabelPos < nMarkPos,strValue表示的是标签中的值,LabelPos表示值中出现”<”的位置,而nMarkPos表示引号出现的位置,结合它们三个变量表示的含义,其实这句话表示如果值里面有”<”并且这个出现在引号之前,那么就说明是标签套标签,也就是存在子标签,这个时候需要递归调用函数,解析子标签的内存,如果这个”<”符号出现在引号之后,则表示它只是值中字符串的一部分,并没有子标签,这个时候就不需要进行递归。
另外还判断了是否存在数组的情况,在json中数组是以一个类似于子对象的方式存储的,所在转化为xml时会将它作为一个子项存储,只是它的标签于父项的标签相同,所以判断数组的语句是当它存在子项时进行的,当得到它是一个数组时,会往后一直遍历,直到下一个标签不同于它,找到数组之后依次将这些值插入数组对象,并将整个数组对象插入到json对象中。
当它只是一个普通的对象时会根据是否存在引号来判断它是否是字符串,然后调用不同的添加项的函数来插入数据
最后将json对象转化为字符串,清空内存并返回函数(万别忘记清理内存)
整个项目的下载地址:下载
使用CJSON库实现XML与JSON格式的相互转化的更多相关文章
- java XML转JSON格式
标签: XML转Json json 2014-05-20 20:55 6568人阅读 评论(6) 收藏 举报 分类: [J2SE基础](20) 代码如下所示,从这个例子中发现了代码库的重要性,如果 ...
- 使用cJSON库解析和构建JSON字符串
使用cJSON库解析和构建JSON字符串 前言 其实之前的两篇博文已经介绍了json格式和如何使用cJSON库来解析JSON: 使用cJSON库解析JSON JSON简介 当时在MCU平台上使用时,会 ...
- 【.net 深呼吸】聊聊WCF服务返回XML或JSON格式数据
有时候,为了让数据可以“跨国经营”,尤其是HTTP Web有关的东东,会将数据内容以 XML 或 JSON 的格式返回,这样一来,不管客户端平台是四大文明古国,还是处于蒙昧时代的原始部落,都可以使用这 ...
- .net WebAPI返回xml、json格式
WebAPI返回xml.json格式简单示例 using System.Net.Http.Formatting; public class TestController : ApiController ...
- 发送xml或json格式的数据给服务器
后台通过context.Request.InputStream来接收 #region 发送消息 + void SendMessage() /// <summary> /// 发送消息 // ...
- Ajax中XML和JSON格式的优劣比较
刚做完一个小的使用Ajax的项目.整个小项目使用JavaScript做客户端,使用PHP做服务器端.利用xmlHttpRequest组件作为交互工具,利用XML作为数据传输的格式.做完后基本做一个简单 ...
- xml转换为json格式时,如何将指定节点转换成数组 Json.NET
使用Json.NET转换xml成json时,如果xml只有单个节点,但json要求是数组形式[], JsonConvert.SerializeXmlNode 并不能自动识别 示例如下: RecordA ...
- xml和JSON格式相互转换的Java实现
依赖的包: json-lib-2.4-jdk15.jar ezmorph-1.0.6.jar xom-1.2.1.jar commons-lang-2.1.jar commons-io-1.3.2.j ...
- SpringBoot RestController 同时支持返回xml和json格式数据
@RestController 默认支持返回json格式数据,即使不做任何配置也能返回json数据 当接口需要支持xml或json两种格式数据时应该怎么做呢? 只要引入 Jackson xml的 ma ...
随机推荐
- Android安全专项-利用androguard分析微信
androguard Androguard经常使用API学习1 安装 做 Android 安全測试之前你应该知道的工具 (一) 分析 ./androlyze.py -s进入分析的交互界面 然后运行 a ...
- action属性注入为null
一. 问题: 今天调试代码遇到问题,使用spring管理action,当中注入了部分原始类型的属性. 配置示比例如以下: <bean class="test.login.test.Lo ...
- AVL树 & 重平衡概念
AVL树是有平衡条件的二叉搜索树.这个平衡条件必须容易保持,而且需要保证树的深度是O(logN). AVL=BBST 作为二叉搜索树的最后一部分,我们来介绍最为经典的一种平衡二叉搜索树:AVL树.回顾 ...
- chrome调试,打完断点后关于JS的几个控制介绍
打完断点之后,关于JS的几个控制介绍. 快捷键:F8 "逐过程执行",继续执行代码,直到遇到下一个断点. 详细解释: 暂停和开始.当设置了断点之后,js的执行就暂停了,如果我们想要 ...
- 由一道bash jail题引出的琐事@_@
关键词:Terminal devices.shell.stdio 题目入口: (需要注册) root@kali:~# ssh level1@24.37.41.154 -p 1016 level1@24 ...
- intellij安装lombok插件,解决注解@Slf4j注入后找不到变量log
1.进入设置 2.搜索插件 3.安装
- 《程序员修炼之道:从小工到专家》【PDF】下载
<程序员修炼之道:从小工到专家>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196340 内容简介 <程序员修炼之道> ...
- 如何优雅地在React项目中使用Redux
前言 或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux 概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与 ...
- margin相关
1.图片与文字对齐问题 如果图片和文字差不多大时,使用兼容性强的margin负值方法. 方法:img{margin:0 3px -3px 0;} 2.div嵌套后margin出现失效(转移)问题 原因 ...
- 【java】彩票中奖码生成器:java.util.Random里的方法public int nextInt(int bound)
package 彩票中奖码生成器; import java.util.Random; public class TestRandom { public static void main(String[ ...