您的位置:首页 > 移动开发

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

2017-02-20 14:28 471 查看
这里是基于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, attrib, attrib_value, flag_index ) {
if ( this.hasNodeAttrib( node, attrib, attrib_value, 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, attrib, attrib_value, 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) {
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;
}

//判断指定的节点中,是含有指定的属性列表
//attrib是一个二维数组键值对 如[["attrib1","value1"],["attrib2","value2"],["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), targetTagName, flagBreadth);
if(n != null) return n;
}
}
else {
for(let i = 0; i < childCnt; i++)
{
let n = this.findNodeByTagName(node.childNodes.item(i), targetTagName, 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;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: