背景
因为服务端给的数据并不是xml,而且服务端要拿的数据是json,所以我们只能xml和json互转,来完成和服务端的对接
xml转json
import XML from './config/jsonxml.js'/*** xml转为json* @param {*} xml*/xmlToJson(xml) {const xotree = new XML.ObjTree()const jsonData = xotree.parseXML(xml)return jsonData},
jsonxml.js
const XML = function() {}// constructorXML.ObjTree = function() {return this
}// class variablesXML.ObjTree.VERSION = '0.23'// object prototypeXML.ObjTree.prototype.xmlDecl = '<?xml version="1.0" encoding="UTF-8" ?>\n'
XML.ObjTree.prototype.attr_prefix = '-'// method: parseXML( xmlsource )XML.ObjTree.prototype.parseXML = function(xml) {let rootif (window.DOMParser) {var xmldom = new DOMParser()// xmldom.async = false; // DOMParser is always sync-modeconst dom = xmldom.parseFromString(xml, 'application/xml')if (!dom) returnroot = dom.documentElement} else if (window.ActiveXObject) {xmldom = new ActiveXObject('Microsoft.XMLDOM')xmldom.async = falsexmldom.loadXML(xml)root = xmldom.documentElement}if (!root) returnreturn this.parseDOM(root)
}// method: parseHTTP( url, options, callback )XML.ObjTree.prototype.parseHTTP = function(url, options, callback) {const myopt = {}for (const key in options) {myopt[key] = options[key] // copy object}if (!myopt.method) {if (typeof myopt.postBody === 'undefined' &&typeof myopt.postbody === 'undefined' &&typeof myopt.parameters === 'undefined') {myopt.method = 'get'} else {myopt.method = 'post'}}if (callback) {myopt.asynchronous = true // async-modeconst __this = thisconst __func = callbackconst __save = myopt.onCompletemyopt.onComplete = function(trans) {let treeif (trans && trans.responseXML && trans.responseXML.documentElement) {tree = __this.parseDOM(trans.responseXML.documentElement)}__func(tree, trans)if (__save) __save(trans)}} else {myopt.asynchronous = false // sync-mode}let transif (typeof HTTP !== 'undefined' && HTTP.Request) {myopt.uri = urlvar req = new HTTP.Request(myopt) // JSANif (req) trans = req.transport} else if (typeof Ajax !== 'undefined' && Ajax.Request) {var req = new Ajax.Request(url, myopt) // ptorotype.jsif (req) trans = req.transport}if (callback) return transif (trans && trans.responseXML && trans.responseXML.documentElement) {return this.parseDOM(trans.responseXML.documentElement)}
}// method: parseDOM( documentroot )XML.ObjTree.prototype.parseDOM = function(root) {if (!root) returnthis.__force_array = {}if (this.force_array) {for (let i = 0; i < this.force_array.length; i++) {this.__force_array[this.force_array[i]] = 1}}let json = this.parseElement(root) // parse root nodeif (this.__force_array[root.nodeName]) {json = [json]}if (root.nodeType != 11) {// DOCUMENT_FRAGMENT_NODEconst tmp = {}tmp[root.nodeName] = json // root nodeNamejson = tmp}return json
}// method: parseElement( element )XML.ObjTree.prototype.parseElement = function(elem) {// COMMENT_NODEif (elem.nodeType == 7) {return}// TEXT_NODE CDATA_SECTION_NODEif (elem.nodeType == 3 || elem.nodeType == 4) {const bool = elem.nodeValue.match(/[^\x00-\x20]/)if (bool == null) return // ignore white spacesreturn elem.nodeValue}let retvalconst cnt = {}// parse attributesif (elem.attributes && elem.attributes.length) {retval = {}for (var i = 0; i < elem.attributes.length; i++) {var key = elem.attributes[i].nodeNameif (typeof key !== 'string') continuevar val = elem.attributes[i].nodeValueif (!val) continuekey = this.attr_prefix + keyif (typeof cnt[key] === 'undefined') cnt[key] = 0cnt[key]++this.addNode(retval, key, cnt[key], val)}}// parse child nodes (recursive)if (elem.childNodes && elem.childNodes.length) {let textonly = trueif (retval) textonly = false // some attributes existsfor (var i = 0; i < elem.childNodes.length && textonly; i++) {const ntype = elem.childNodes[i].nodeTypeif (ntype == 3 || ntype == 4) continuetextonly = false}if (textonly) {if (!retval) retval = ''for (var i = 0; i < elem.childNodes.length; i++) {retval += elem.childNodes[i].nodeValue}} else {if (!retval) retval = {}for (var i = 0; i < elem.childNodes.length; i++) {var key = elem.childNodes[i].nodeNameif (typeof key !== 'string') continuevar val = this.parseElement(elem.childNodes[i])if (!val) continueif (typeof cnt[key] === 'undefined') cnt[key] = 0cnt[key]++this.addNode(retval, key, cnt[key], val)}}}return retval
}// method: addNode( hash, key, count, value )XML.ObjTree.prototype.addNode = function(hash, key, cnts, val) {if (this.__force_array[key]) {if (cnts == 1) hash[key] = []hash[key][hash[key].length] = val // push} else if (cnts == 1) {// 1st siblinghash[key] = val} else if (cnts == 2) {// 2nd siblinghash[key] = [hash[key], val]} else {// 3rd sibling and morehash[key][hash[key].length] = val}
}// method: writeXML( tree )XML.ObjTree.prototype.writeXML = function(tree) {const xml = this.hash_to_xml(null, tree)return this.xmlDecl + xml
}// method: hash_to_xml( tagName, tree )XML.ObjTree.prototype.hash_to_xml = function(name, tree) {const elem = []const attr = []for (const key in tree) {if (!tree.hasOwnProperty(key)) continueconst val = tree[key]if (key.charAt(0) != this.attr_prefix) {if (typeof val === 'undefined' || val == null) {elem[elem.length] = `<${key} />`} else if (typeof val === 'object' && val.constructor == Array) {elem[elem.length] = this.array_to_xml(key, val)} else if (typeof val === 'object') {elem[elem.length] = this.hash_to_xml(key, val)} else {elem[elem.length] = this.scalar_to_xml(key, val)}} else {attr[attr.length] = ` ${key.substring(1)}="${this.xml_escape(val)}"`}}const jattr = attr.join('')let jelem = elem.join('')if (typeof name === 'undefined' || name == null) {// no tag} else if (elem.length > 0) {if (jelem.match(/\n/)) {jelem = `<${name}${jattr}>\n${jelem}</${name}>\n`} else {jelem = `<${name}${jattr}>${jelem}</${name}>\n`}} else {jelem = `<${name}${jattr} />\n`}return jelem
}// method: array_to_xml( tagName, array )XML.ObjTree.prototype.array_to_xml = function(name, array) {const out = []for (let i = 0; i < array.length; i++) {const val = array[i]if (typeof val === 'undefined' || val == null) {out[out.length] = `<${name} />`} else if (typeof val === 'object' && val.constructor == Array) {out[out.length] = this.array_to_xml(name, val)} else if (typeof val === 'object') {out[out.length] = this.hash_to_xml(name, val)} else {out[out.length] = this.scalar_to_xml(name, val)}}return out.join('')
}// method: scalar_to_xml( tagName, text )XML.ObjTree.prototype.scalar_to_xml = function(name, text) {if (name == '#text') {return this.xml_escape(text)}return `<${name}>${this.xml_escape(text)}</${name}>\n`
}// method: xml_escape( text )XML.ObjTree.prototype.xml_escape = function(text) {return `${text}`.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')
}export default XML
json 转为xml
const getIncoming = (id, data) => {return data.filter(item => item.targetRef === id).map(items => items.id)
}
const getOutGoing = (id, data) => {return data.filter(item => item.sourceRef === id).map(items => items.id)
}
const getLabel = (data, labelStyle) => {const keyWord = ['isBold', 'isItalic', 'isStrikeThrough', 'isUnderline', 'fontFamily', 'size']const arr = data.filter(item => {return keyWord.find(key => {return key in labelStyle})})return arr.map(item => {const obj = {}keyWord.forEach(key => {if (labelStyle[key]) {obj[key === 'fontFamily' ? 'name' : key] = labelStyle[key] || ''}})return {'-id': item.id,'omgdc:Font': obj}})
}
export function convertJsonToBpmn(jsonData) {if (!jsonData || !Object.keys(jsonData).length) return {}const result = {definitions: {'-xmlns': 'http://www.omg.org/spec/BPMN/20100524/MODEL','-xmlns:bpmndi': 'http://www.omg.org/spec/BPMN/20100524/DI','-xmlns:omgdi': 'http://www.omg.org/spec/DD/20100524/DI','-xmlns:omgdc': 'http://www.omg.org/spec/DD/20100524/DC','-xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance','-xmlns:bioc': 'http://bpmn.io/schema/bpmn/biocolor/1.0','-xmlns:color': 'http://www.omg.org/spec/BPMN/non-normative/color/1.0','-id': 'sid-38422fae-e03e-43a3-bef4-bd33b32041b2','-targetNamespace': 'http://bpmn.io/bpmn','-exporter': 'bpmn-js (https://demo.bpmn.io)','-exporterVersion': '5.1.2',process: {'-id': 'Process_1','-isExecutable': 'true',task: [],sequenceFlow: []},'bpmndi:BPMNDiagram': {'-id': 'BpmnDiagram_1','bpmndi:BPMNPlane': {'-id': 'BpmnPlane_1','-bpmnElement': 'Process_1','bpmndi:BPMNShape': [],'bpmndi:BPMNEdge': []}},'bpmndi:BPMNLabelStyle': {}}}// Convert tasksjsonData.nodeLists.forEach(task => {const taskId = task.config.idconst incoming = getIncoming(taskId, jsonData.lines)const outGoing = getOutGoing(taskId, jsonData.lines)const obj = {'-id': taskId}if (incoming.length > 1) {obj.incoming = incoming} else if (incoming.length === 1) {obj.incoming = incoming[0]}if (outGoing.length > 1) {obj.outgoing = outGoing} else if (outGoing.length === 1) {obj.outgoing = outGoing[0]}result.definitions.process.task.push(obj)const { x, y, width, height, labelStyle } = task.configconst element = {'-id': `${taskId}_di`,'-bpmnElement': taskId,'omgdc:Bounds': {'-x': x,'-y': y,'-width': width,'-height': height},'bpmndi:BPMNLabel': {}}if (labelStyle && Object.keys(labelStyle).length) {const { x, y, width, height, id } = labelStyleelement['bpmndi:BPMNLabel']['-labelStyle'] = idelement['bpmndi:BPMNLabel']['omgdc:Bounds'] = {'-x': x,'-y': y,'-width': width,'-height': height}result.definitions['bpmndi:BPMNLabelStyle'] = getLabel(jsonData.nodeLists, labelStyle)}// Convert BPMN shapesresult.definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNShape'].push(element)})// Convert sequence flowsjsonData.lines.forEach(line => {const sequenceFlowId = line.idconst sourceRef = line.sourceRefconst targetRef = line.targetRefresult.definitions.process.sequenceFlow.push({'-id': `${sequenceFlowId}`,'-name': line.name,'-sourceRef': sourceRef,'-targetRef': targetRef})// Convert BPMN edgesresult.definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNEdge'].push({'-id': `${sequenceFlowId}_di`,'-bpmnElement': sequenceFlowId,'omgdi:waypoint': line.point.map(p => {return { '-x': p.x, '-y': p.y }}),'bpmndi:BPMNLabel': {'omgdc:Bounds': {'-x': line.x,'-y': line.y,'-width': line.width,'-height': line.height}}})})return result
}