vue项目快速实现后端接口返回的xml格式的数据进行解析
相关背景:
老项目重构,后端返回xml格式数据。
前端有现有的vue项目底层框架可以复用,现有框架支持对后端返回的json数据进行解析,需要调整的就是对xml格式数据的解析。
前端对后端接口的请求使用axios进行封装,且有mock数据方便本地联调开发。
解决方案:
封装xml解析相关方法;
根据后端接口返回数据格式边写xml文件进行后端数据mock;
mock数据的实现:
json格式的数据可以直接编写json格式的数据进行模拟,可以很方便的进行解析。
xml格式的数据如果直接写成字符串格式的,更新管理起来会比较麻烦,因此可以直接编写xml文件进行模拟。
对于mock接口数据的xml文件,可以在mock数据请求封装中直接对xml文件进行读取解析。
xml解析相关函数封装:
xmlLoad.js
1 /** 2 * 加载xml文件 3 * @param {Object} dname 4 */ 5 function loadXMLDoc(dname) { 6 let xhttp 7 if (window.XMLHttpRequest) { 8 xhttp = new XMLHttpRequest(); 9 } else { 10 xhttp = new ActiveXObject("Microsoft.XMLHTTP"); 11 } 12 xhttp.open("GET", dname, false); 13 xhttp.send(); 14 return xhttp.responseXML; 15 } 16 17 /** 18 * xml字符串转换xml对象数据 19 * @param {Object} xmlStr 20 */ 21 function xmlStr2XmlObj(xmlStr) { 22 var xmlObj = {}; 23 if (document.all) { 24 var xmlDom = new ActiveXObject("Microsoft.XMLDOM"); 25 xmlDom.loadXML(xmlStr); 26 xmlObj = xmlDom; 27 } else { 28 xmlObj = new DOMParser().parseFromString(xmlStr, "text/xml"); 29 } 30 return xmlObj; 31 } 32 33 /** 34 * xml直接转换json数据 35 * @param {Object} xml 36 */ 37 function xmlObj2json(xml) { 38 try { 39 var obj = {}; 40 if (xml.children.length > 0) { 41 for (var i = 0; i < xml.children.length; i++) { 42 var item = xml.children.item(i); 43 var nodeName = item.nodeName; 44 if (typeof(obj[nodeName]) == "undefined") { 45 obj[nodeName] = xmlObj2json(item); 46 } else { 47 if (typeof(obj[nodeName].push) == "undefined") { 48 var old = obj[nodeName]; 49 obj[nodeName] = []; 50 obj[nodeName].push(old); 51 } 52 obj[nodeName].push(xmlObj2json(item)); 53 } 54 } 55 } else { 56 obj = xml.textContent; 57 } 58 return obj; 59 } catch (e) { 60 console.log(e.message); 61 } 62 } 63 64 /** 65 * xml字符串转换json数据 66 * @param {Object} xml 67 */ 68 function xmlStr2json(xml) { 69 var xmlObj = xmlStr2XmlObj(xml); 70 var jsonObj = {}; 71 if (xmlObj.childNodes.length > 0) { 72 jsonObj = xmlObj2json(xmlObj); 73 } 74 return jsonObj; 75 } 76 77 export default { 78 loadXMLDoc, 79 xmlStr2XmlObj, 80 xmlObj2json, 81 xmlStr2json 82 }
mock后端返回数据:
mocklist.xml
<?xml version="1.0" encoding="utf-8"?> <Apilist> <!--首页banner--> <searchBanners> <ApiResult> <ret_code>000000</ret_code> <ret_msg>请求成功</ret_msg> <datas> <Banner> <banner_id>001</banner_id> <set_id>001</set_id> <num>0</num> <pic_url>http://xxx.com.jpg</pic_url> <link_type>0</link_type> <link_id>http://xxx.com</link_id> <description>描述</description> </Banner> <Banner> <banner_id>002</banner_id> <set_id>002</set_id> <num>0</num> <pic_url>http://xxx.com.jpg</pic_url> <link_type>1</link_type> <link_id>/myTask</link_id> <description>描述</description> </Banner> </datas> </ApiResult> </searchBanners> ... </Apilist>
如上,高亮部分的标签可以看做是mock接口的名称,与前端对接口请求的封装函数名对应,如下:
request.js
import request from '@api/request' const { errorToast, http } = request /** * 导出接口请求 * noNeedLogin: true 无需登录 * noPreError: true 无需预处理错误信息 */ export default { errorToast, //检验用户登录有效性 searchBanners(params) { return http({ api: "searchBanners", data: params }) }, ......
注:经验证,xml文件需要放在static文件夹中,本地编译vue项目后,能直接在浏览器中访问该文件,以便于xml文件的读取。
xml文档中mock数据的读取:
request.js
1 import axios from "axios" 2 ...... 3 import xmlLoad from '@assets/js/xmlLoad' 4 /** 5 * 封装mock数据模拟接口请求 6 */ 7 let http2; 8 if (isLocal) http2 = (params) => { 9 var self = this 10 let dname = location.origin + '/static/mocklist.xml' 11 return new Promise((resolve, reject) => { 12 //读取xml中的数据 13 let xmlNodes = xmlLoad.loadXMLDoc(dname) //xml数据读取 14 if(!xmlNodes) return; 15 let xmlJson = xmlLoad.xmlObj2json(xmlNodes) //xml转换为json格式数据 16 let mocklist = xmlJson['Apilist'] //mock数据列表 17 setTimeout(() => { 18 //获取当前访问接口名及mock数据 19 let key = params.api 20 var data = mocklist[key].ApiResult 21 resolve(data) 22 }) 23 } 24 25 export default { 26 errorToast, 27 http: isLocal ? http2 : http 28 }
后端接口真实数据的读取:
request.js
1 import axios from "axios" 2 import xmlLoad from '@assets/js/xmlLoad' 3 ...... 4 5 /** 6 * 封装服务器端接口请求方法 7 */ 8 const http = (params) => { 9 return new Promise((resolve, reject) => { 10 axios.request({ 11 url: '/xxxx.do',//后端访问接口地址 12 params: params.data, 13 method: params.method || 'POST' 14 }).then(function(res) { 15 //解析接口返回的xml字符串数据 16 let xmlStr = res.data; 17 let xmlJson = xmlLoad.xmlStr2json(xmlStr) 18 let data = xmlJson && xmlJson["ApiResult"] 19 if (res.status == 200 && data) { 20 ...... 21 resolve(data) 22 } else { 23 errorToast(); 24 console.log(data) 25 } 26 }).catch(function(e) { 27 errorToast(); 28 reject(e) 29 }); 30 }) 31 } 32 33 /** 34 * 封装mock数据模拟接口请求 35 */ 36 let http2; 37 ...... 38 39 export default { 40 errorToast, 41 http: isLocal ? http2 : http 42 }
如上,即实现了对后端接口数据的模拟,方便本地开发,同时对xml格式数据处理方面也只是在请求封装中进行,页面中的实现未受影响。
注意事项:
对于xml到json的转换,因xml本身并没有数组的概念,所以需要注意我们需要的“数组”如果只有一条数据的异常处理。
1 <datas> 2 <UserTask> 3 <task_tag>001</task_tag> 4 <task_term>001</task_term> 5 <task_title>xxxx</task_title> 6 <task_status>0</task_status> 7 <task_extra_info>{"tag_name":"xxxx","tag_pic_url":"https://xxxx.jpg","task_begin_time":"2020.06.20","task_end_time":"2020.07.20"}</task_extra_info> 8 </UserTask> 9 </datas>
如上面代码,如果只有一个 UserTask ,那么解析出来将是一个Object对象:
//只有一个UserTask data:{ UserTask:{ ...... } }
如果有多个,则是数组:
//有多个UserTask data:{ UserTask:[{ ...... },{ ...... },{ ...... }] }
对于这个情况,可以封装一个函数进行转换,以方便前端进行页面布局与数据渲染。代码如下:
1 /** 2 * xml解析后的列表转换为js的数组 3 * @param {Object} xmlList 4 */ 5 function xmlListToArr(xmlList) { 6 let targetArr = [] 7 if (xmlList.constructor == Array) { 8 targetArr = xmlList 9 } else { 10 targetArr[0] = xmlList 11 } 12 return targetArr 13 }
如上,可以封装在公共函数里边,在页面中有从后端请求的列表数据需要渲染时,就可以调用这个函数进行数据处理。
这里还需要注意这些问题:
- 大部分列表数据都需要进行数组化处理:毕竟大部分列表的数据都当然,如果是几个简单的图片列表的展示,那可以考虑单个图片的展示,不必要把单个图片也转换成数组;
- 数组化处理操作在具体页面具体业务代码中进行:列表数据的处理由于xml中没有数组的概念,所以没办法很好的进行集中封装处理,因此可以在具体页面的具体数据进行处理;
- 可以集中封装处理的情况:如果知道后端返回接口所有列表类数据都严格包含某个字符串,如list,那么可以直接在xml解析函数中进行拦截处理就好了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通