背景
因为服务端给的数据并不是xml,而且服务端要拿的数据是json,所以我们只能xml和json互转,来完成和服务端的对接文章来源:https://www.toymoban.com/news/detail-677801.html
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文章来源地址https://www.toymoban.com/news/detail-677801.html
const XML = function() {}
// constructor
XML.ObjTree = function() {
return this
}
// class variables
XML.ObjTree.VERSION = '0.23'
// object prototype
XML.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 root
if (window.DOMParser) {
var xmldom = new DOMParser()
// xmldom.async = false; // DOMParser is always sync-mode
const dom = xmldom.parseFromString(xml, 'application/xml')
if (!dom) return
root = dom.documentElement
} else if (window.ActiveXObject) {
xmldom = new ActiveXObject('Microsoft.XMLDOM')
xmldom.async = false
xmldom.loadXML(xml)
root = xmldom.documentElement
}
if (!root) return
return 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-mode
const __this = this
const __func = callback
const __save = myopt.onComplete
myopt.onComplete = function(trans) {
let tree
if (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 trans
if (typeof HTTP !== 'undefined' && HTTP.Request) {
myopt.uri = url
var req = new HTTP.Request(myopt) // JSAN
if (req) trans = req.transport
} else if (typeof Ajax !== 'undefined' && Ajax.Request) {
var req = new Ajax.Request(url, myopt) // ptorotype.js
if (req) trans = req.transport
}
if (callback) return trans
if (trans && trans.responseXML && trans.responseXML.documentElement) {
return this.parseDOM(trans.responseXML.documentElement)
}
}
// method: parseDOM( documentroot )
XML.ObjTree.prototype.parseDOM = function(root) {
if (!root) return
this.__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 node
if (this.__force_array[root.nodeName]) {
json = [json]
}
if (root.nodeType != 11) {
// DOCUMENT_FRAGMENT_NODE
const tmp = {}
tmp[root.nodeName] = json // root nodeName
json = tmp
}
return json
}
// method: parseElement( element )
XML.ObjTree.prototype.parseElement = function(elem) {
// COMMENT_NODE
if (elem.nodeType == 7) {
return
}
// TEXT_NODE CDATA_SECTION_NODE
if (elem.nodeType == 3 || elem.nodeType == 4) {
const bool = elem.nodeValue.match(/[^\x00-\x20]/)
if (bool == null) return // ignore white spaces
return elem.nodeValue
}
let retval
const cnt = {}
// parse attributes
if (elem.attributes && elem.attributes.length) {
retval = {}
for (var i = 0; i < elem.attributes.length; i++) {
var key = elem.attributes[i].nodeName
if (typeof key !== 'string') continue
var val = elem.attributes[i].nodeValue
if (!val) continue
key = this.attr_prefix + key
if (typeof cnt[key] === 'undefined') cnt[key] = 0
cnt[key]++
this.addNode(retval, key, cnt[key], val)
}
}
// parse child nodes (recursive)
if (elem.childNodes && elem.childNodes.length) {
let textonly = true
if (retval) textonly = false // some attributes exists
for (var i = 0; i < elem.childNodes.length && textonly; i++) {
const ntype = elem.childNodes[i].nodeType
if (ntype == 3 || ntype == 4) continue
textonly = 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].nodeName
if (typeof key !== 'string') continue
var val = this.parseElement(elem.childNodes[i])
if (!val) continue
if (typeof cnt[key] === 'undefined') cnt[key] = 0
cnt[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 sibling
hash[key] = val
} else if (cnts == 2) {
// 2nd sibling
hash[key] = [hash[key], val]
} else {
// 3rd sibling and more
hash[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)) continue
const 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 tasks
jsonData.nodeLists.forEach(task => {
const taskId = task.config.id
const 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.config
const 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 } = labelStyle
element['bpmndi:BPMNLabel']['-labelStyle'] = id
element['bpmndi:BPMNLabel']['omgdc:Bounds'] = {
'-x': x,
'-y': y,
'-width': width,
'-height': height
}
result.definitions['bpmndi:BPMNLabelStyle'] = getLabel(jsonData.nodeLists, labelStyle)
}
// Convert BPMN shapes
result.definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNShape'].push(element)
})
// Convert sequence flows
jsonData.lines.forEach(line => {
const sequenceFlowId = line.id
const sourceRef = line.sourceRef
const targetRef = line.targetRef
result.definitions.process.sequenceFlow.push({
'-id': `${sequenceFlowId}`,
'-name': line.name,
'-sourceRef': sourceRef,
'-targetRef': targetRef
})
// Convert BPMN edges
result.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
}
到了这里,关于如何自己实现一个丝滑的流程图绘制工具(五)bpmn的xml和json互转的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!