appium的source返回的xml字符串处理的工具函数

前端之家收集整理的这篇文章主要介绍了appium的source返回的xml字符串处理的工具函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这里是基于node的xmldom上扩展的工具,在使用appium的时候,常常需要用source功能来分析当前上下文,所以扩展了若干函数,用于分析。

这些代码是基于node 6.9.x javascript ES6语法实现。(关于如何在node使用ES6的语法,请参考我的前文:js笔记四:node 6.9.x for gulp完整配置过程

完成代码如下:xml_utils.js

import { DOMParser } from "xmldom";

xml_utils = {};
//------------------------------------------------------------------------------
//解析XML字符串,并返回XML的dom对象
xml_utils.parseFromString = function ( xmlstring ) {
    return new DOMParser().parseFromString( xmlstring );
}

//判断是否有该属性的值
xml_utils.hasNodeAttrib = function ( node,attrib,attrib_value,flag_index ) {
    var nCnt = ( node && node.attributes ) ? node.attributes.length : 0;
    for ( var i = 0; i < nCnt; i++ ) {
        var attr = node.attributes[i];
        //if (attr.name == attrib) {
        //    console.log("found attrib:" + attrib + "=" + attr.value + ",dest=" + attrib_value);
        //}
        if ( attr.name != attrib ) continue;
        if ( flag_index === true ) {
            if ( attr.value.indexOf( attrib_value ) >= 0 ) return true;
        }
        else {
            if ( attr.value.trim() == attrib_value ) return true;
        }
    }
    return false;
}

//取指定的属性
xml_utils.getNodeAttrib = function ( node,attrib ) {
    var nCnt = ( node && node.attributes ) ? node.attributes.length : 0;
    for ( var i = 0; i < nCnt; i++ ) {
        var attr = node.attributes[i];
        if ( attr.name == attrib ) return attr;
    }
    return null;
}

//前一个节点
xml_utils.getNodePre = function ( node ) {
    if ( node == null || node.parentNode == null ) return null;
    var pNode = node.parentNode;
    var nCnt = pNode.childNodes ? pNode.childNodes.length : 0;
    var nIndex = -1;
    for ( var i = 0; i < nCnt; i++ ) {
        if ( pNode.childNodes.item( i ) === node ) {
            nIndex = i;
            break;
        }
    }
    if ( nIndex > 0 ) {
        var nNextIndex = nIndex - 1;
        if ( nNextIndex < nCnt ) return pNode.childNodes.item( nNextIndex );
    }
    return null;
}


//下一个节点
xml_utils.getNodeNext = function ( node ) {
    if ( node == null || node.parentNode == null ) return null;
    var pNode = node.parentNode;
    var nCnt = pNode.childNodes ? pNode.childNodes.length : 0;
    var nIndex = -1;
    for ( var i = 0; i < nCnt; i++ ) {
        if ( pNode.childNodes.item( i ) === node ) {
            nIndex = i;
            break;
        }
    }
    if ( nIndex >= 0 ) {
        var nNextIndex = nIndex + 1;
        if ( nNextIndex < nCnt ) return pNode.childNodes.item( nNextIndex );
    }
    return null;
}

//查找指定属性的节点
xml_utils.findNodeByAttribName = function ( node,flag_index ) {
    if ( this.hasNodeAttrib( node,flag_index ) ) return node;
    //便利所有的子节点  使用深度遍历的方式
    var nChildCnt = node.childNodes ? node.childNodes.length : 0;
    for ( var i = 0; i < nChildCnt; i++ ) {
        var n = node.childNodes.item( i );
        var nRet = this.findNodeByAttribName( n,flag_index );
        if ( nRet ) {
            return nRet;
        }
    }
    return null;
}

//将节点数组中指定的属性值,放到集合中
xml_utils.nodesAttribToSet = function (nodeArray,attribName) {
    let retSet = new Set();
    for(let n of nodeArray)    
    {
        if(n.attrMap)
        {
            let v = n.attrMap.get(attribName);
            if(v) retSet.add(v);
        }
        else
        {
            let nCnt = n.attributes ? n.attributes.length : 0;
            for(let i = 0;i < nCnt;i++) {
                let attr = n.attributes.item(i);
                if(attr && attr.name.trim() == attribName)
                {
                    retSet.add(attr.value.trim());
                    break;
                }
            }
        }
    }
    return retSet;
}

//通过指定的函数,来确定要设的值
xml_utils.nodesAttribToSetEx = function (nodeArray,getFunction) {
    if(typeof getFunction === "function") {
        let retSet = new Set();
        for(let n of nodeArray)    
        {
            let [r,txt] = getFunction(n);
            if(r) retSet.add(txt.trim());
        }
        return retSet;    
    }
    else if(Array.isArray(getFunction)) {  //如果传入的是一个数组
        return xml_utils.nodesAttribToSetEx(nodeArray,new Set(getFunction));
    }
    else if(getFunction instanceof Set) {
        let s = getFunction;
        let retSet = new Set();
        for (let n of nodeArray) {
            let nCnt = n.attributes ? n.attributes.length : 0;
            for (let i = 0; i < nCnt; i++) {
                let attr = n.attributes.item(i);
                if (attr && s.has(attr.name.trim())) {
                    if (!attr.value) continue;  //如果属性值不存在
                    let v = attr.value.trim();
                    if (v.length == 0) continue; //如果为空串
                    retSet.add(v);
                }
            }
        }  
        return retSet;     
    }
    else return new Set();
    //if(!(typeof getFunction ==="function")) return retSet;
}

//判断是否有指定含有属性的节点 这里会要求指定节点名称,也就是class 其它需要的属性,则要另外判断
//node表示是当前的节点  
//要查找的节点名称属性列表 [{class:"xxx",y:"134"},{class:"yyyy"}]
//返回符合条件的节点数组
//这里的方法,类似于 getNodesByAttrib 但是这个方法性能上做了优化,参数更加直观
xml_utils.getNodesByClass = function(node,classNameList) {
    let r = [];
    if(!node) r;

    let cmap = new Map();           //class和class条件列表

    if(Array.isArray(classNameList)) {
        for(let e of classNameList) {  //将每个条件取出来
            let classValue = e.class;  
            if(classValue) 
            {
                let nCnt = 0;
                for(let i in e) nCnt ++;  //计算需要比较属性数量,并保存,用于后面比较
                cmap.set(classValue,{c:e,count:nCnt}); 
            }
        }
    }

    function check(n) {
        if(!n) return false;  //如果节点为null,则返回false

        let attrCnt = xml_utils.getAttributeCount(n);
        if(attrCnt == 0) return false;  //没有没有任何属性

        let e = cmap.get(n.nodeName);     //取条件列表,如果没有它的条件列表,则返回false
        if(!e) return false;  
        let c = e.c;  //条件列表

        //构建属性映射表
        let foundCount = 0;
        for(let i = 0; i < attrCnt; i++) {
            let attr = n.attributes[i];            
            let cValue = c[attr.name];
            if(cValue === undefined) continue;      //如果这个不是条件之一,则下一个
            if(cValue === null || cValue === attr.value) foundCount++;
            else return false;      //如果找到属性存在,但是属性值不相同,则表示不合条件
        }
        //计算条件的数量
        return e.count == foundCount;
    }
    //编历所有节点
    function findNode(n,r) {
        if(check(n)) r.push(n);
        let childCnt = xml_utils.getChildNodeCount(n);
        for(let i = 0; i < childCnt; i++) {
            findNode(n.childNodes.item(i),r);
        }
    }
    findNode(node,r);
    return r;
}

//判断是否有指定含有属性的节点
//node表示是当前的节点
//attrib是一个二维数组键值对  如[["attrib1","value1"],["attrib2","value2"],["attrib3"]]
//返回符合条件的节点数组
xml_utils.getNodesByAttrib = function (node,attrib) {
    let r = [];
    if(!node) r;
    //构造条件
    let c = {};
    c.map = new Map();
    c.set = new Set();
    if(Array.isArray(attrib)) {
        for(let e of attrib) {
            if(!Array.isArray(e)) continue;
            if(e.length == 1) c.set.add(e[0]);
            else if(e.length == 2) {
                let mm = c.map.get(e[0]);
                if(!mm) {
                    mm = new Set();
                    c.map.set(e[0],mm);
                }
                mm.add(e[1]);
            }
        }
    }
    //检查有没有符合属性的节点
    function check(n) {
        let attrCnt = xml_utils.getAttributeCount(n);
        //编历所有属性,判断是不是符合要求
        for(let i = 0; i < attrCnt; i++) {
            let attr = n.attributes[i];
            if(c.set.has(attr.name)) return true;
            let o = c.map.get(attr.name);
            if(o && o.has(attr.value.trim())) return true;
        }
        return false;
    }
    //编历所有节点
    function findNode(n,r);
    return r;
}

//判断指定的节点中,是含有指定的属性列表
//attrib是一个二维数组键值对  如[["attrib1",["attrib3"]]
xml_utils.hasAttribInNode = function (node,attrib) {
    if(!Array.isArray(attrib)) return false;
    let nAttribCount = (node && node.attributes) ? node.attributes.length : 0;
    if(nAttribCount <= 0) return false;
    let mapAttr = new Map();
    for(let i = 0;i < nAttribCount;i++) {
        let e = node.attributes[i];
        mapAttr.set(e.name.trim(),e.value.trim());
    }
    let bRet = true;
    for(let i = 0;i < attrib.length;i++) {
        let attr = attrib[i];
        if(!Array.isArray(attr)) continue;  //如果不是数组,则忽略
        if(attr.length <= 0) continue;        //如果数组为空,则忽略
        if(attr.length == 1) //如果只有一个属性,则判断该属性是否存在
        {
            if(!mapAttr.has(attr[0])) return false;
        }
        else {
            if(!(mapAttr.get(attr[0]) === attr[1])) return false;
        }
    }
    node.attrMap = mapAttr;
    return bRet;
}
//将一个xml节点含属性转为字符  不含比子节点
xml_utils.nodeAttribToString = function (node) {
    let strRet = "<" + (node.tagName || "") + " ";
    let nAttribCount = (node && node.attributes) ? node.attributes.length : 0;
    for(let i = 0;i < nAttribCount;i++) {
        let e = node.attributes[i];
        strRet = strRet + ' ' + e.name + '="' + e.value + '"';
    }
    strRet += " />"
    return strRet;
}


//取找tagName的第一个节点  
/**
 * 默认是深度遍历
 * @param node 开始查找的节点
 * @param targetTagName 节点的名称
 * @param flagBreadth 广度遍历的标志 @default = false
 */
xml_utils.findNodeByTagName = function (node,targetTagName,flagBreadth = false) {
	if(!node) return null;
	if(node.tagName === targetTagName) {
        console.log("找到节点1:",xml_utils.nodeAttribToString(node));
        return node;
    }
	let childCnt = node.childNodes?node.childNodes.length:0;
    if(flagBreadth){
        for(let i = 0; i < childCnt; i++)
        {
            let childNode = node.childNodes.item(i);
            if(childNode.tagName === targetTagName) {
                console.log("找到节点2:",xml_utils.nodeAttribToString(childNode));
                return childNode;
            }
        }
        for(let i = 0; i < childCnt; i++)
        {
            let n = this.findNodeByTagName(node.childNodes.item(i),flagBreadth);
            if(n != null) return n;
        }
    }
    else {
        for(let i = 0; i < childCnt; i++)
        {
            let n = this.findNodeByTagName(node.childNodes.item(i),flagBreadth);
            if(n != null) return n;
        }
    }
	return null;
}

//取节点的子节点的个数
xml_utils.getChildNodeCount = function(node) {
    if(!node) return 0;
    if(!node.childNodes) return 0;
    return node.childNodes.length;
}
//取节点的属性个数
xml_utils.getAttributeCount = function(node) {
    if(!node) return 0;
    if(!node.attributes) return 0;
    return node.attributes.length;
}
//取指定下标的子节点
xml_utils.getChildNodeByIndex = function (node,index) {
    if(!node) return null;
    if(!node.childNodes) return null;
    return node.childNodes.item(index);
}
//取指定下标的属性
xml_utils.getAttributeByIndex = function(node,index) {
    if(node) return null;
    if(!node.attributes) return null;
    return node.attributes[index];
}
//打印指定node XML
//这个是用于测试
xml_utils.dumpXmlNode = function (pre,node) {
    pre = pre || "";
    let tagName = (node && node.tagName)?node.tagName:"";
    let nChildCnt = xml_utils.getChildNodeCount(node);
    let nAttrCnt = xml_utils.getAttributeCount(node);
    let s = `${pre}<${tagName}`;
    for(let i = 0; i < nAttrCnt; i++) {
        let attr = node.attributes[i];
        s = s + ` ${attr.name}="${attr.value}"`;
    }
    if(nChildCnt > 0) {
        s = s + ">";
        console.log(s);
        for(let i = 0; i < nChildCnt; i++)
        {
            xml_utils.dumpXmlNode(pre + "  ",node.childNodes.item(i));
        }
        console.log(`${pre}</${tagName}>`);
    } else {
        s = s + "/>";
        console.log(s);
    }
}
export { xml_utils};
export default xml_utils;
原文链接:https://www.f2er.com/xml/294424.html

猜你在找的XML相关文章