在解决了如何转化XML格式进入参数这个大问题后,接着我们要介绍一下XML系列函数,帮助我们对XML格式进行操作。
1)lr_xml_get_values
该函数的作用是帮助我们从一个XML格式中取出我们所需要的某一个节点或者多个节点的值。如果你无法很简单地看出节点层次,可以将XML源文件丢到IE浏览器中,这样你会看到浏览器帮助你自动解析成为树形模式,可以折叠的部分都是节点名。
现在我们需要获得上面XML中的"性能测试进阶指南"字段,应该怎么写呢?通过浏览器我们可以看到所需要的字段是在bookstore节点下的book节点下的title属性中。那么函数就需要这样写:
lr_xml_get_values("XML={xmlparam}",
"FastQuery=/bookstore/book/title",
"ValueParam=title",
LAST);
FastQuery是说明查询节点的方式,XML=说明了被查询的XML参数名,ValueParam是指该函数查找出的值保存在title这个参数中,该函数还自带返回,所以代码可以这样写:
int gvcount;
xmlstring="<?xml version=\"1.0\" encoding=\"GB2312\"?>…";//XML正文略
lr_save_string(xmlstring,"xmlparam" );
gvcount=lr_xml_get_values("XML={xmlparam}",
"FastQuery=/bookstore/book/title",
"ValueParam=title",
"NotFound=continue",
LAST);
if(gvcount==0)
lr_output_message("this is no value be found in the XML source");
else
lr_output_message("find the value in the XML source");
在这个代码中我们定义了新的整数变量gvcount,这个变量里面存放了lr_xml_get_ values查询符合条件的记录个数。这里在函数中添加了一个NotFound=continue,该属性的作用是当无法查询到内容时不要出现error错误,继续脚本。在代码的最后有一个if分支语句,用来判断是否存在符合查询条件的内容。
当我们需要多个符合条件的XML节点属性时可以这样写,
gvcount=lr_xml_get_values("XML={xmlparam}",
"Query=/bookstore/book/title",
"ValueParam=title",
"SelectAll=yes",
"NotFound=continue",
LAST);
当需要多个符合节点条件的内容时,我们需要先将FastQuery修改为Query模式,然后添加SelectALL=yes属性,当这个查询执行后,我们会看到这样的日志结果:
Action.c(48): Notify: Saving Parameter "title_1 = 性能测试进阶指南".
Action.c(48): Notify: Saving Parameter "title_2 = 性能测试进阶指南2".
而在gvcount变量中存放的值为2。这个时候我们还不能直接使用title这个参数,因为它还不是参数数组,所以需要手工编写这样的代码为这个参数补充一个参数数组格式:
lr_save_int(gvcount,"title_count");
这样我们就生成了一个title的参数数组,如果需要对这个返回值进行处理,就可以使用前面的参数数组进行操作了。
2)lr_xml_extract
这个函数和上面介绍的函数其实作用差不多,区别在于lr_xml_get_values返回的是节点的属性值,而lr_xml_extract返回的是XML节点。
我们继续编写获得id属性值的代码:
lr_xml_extract("XML={xmlparam}",
"Query=/bookstore/book/id",
"NotFound=continue",
"XMLFragmentParam=Result",
LAST);
这里我们查询的节点为/bookstore/book/id,查询的结果保存到Result参数中,日志结果为:
Action.c(67): Notify: Parameter Substitution: parameter "Result" = "<id>No1</id>"
可以看到不一样的地方是在返回的结构上,lr_xml_get_values如果对这个节点处理,那么结果是No1,而lr_xml_extract返回的是<id>No1</id>。
这里我们研究一个更复杂的情况,如果我们需要先随机从book上选择一个记录,然后在这个记录上再读取各个属性的值,那么这个代码我们应该怎么实现?
首先我们要使用lr_xml_extract来获得符合条件的随机记录,然后对这个符合条件记录的XML再去取值,代码如下:
int xecount;
char *xmlstring;
xmlstring="<?xml version=\"1.0\" encoding=\"GB2312\"?>…";//XML正文略
lr_save_string( xmlstring,"xmlparam");
xecount=lr_xml_extract("XML={xmlparam}",
"Query=/bookstore/book",
"XMLFragmentParam=Result",
"SelectAll=yes",
"NotFound=continue",
LAST);
lr_save_int(xecount,"Result_count");
lr_save_string(lr_paramarr_random("Result"),"rxmlparam");
得到了随机的某个记录,接着就要使用lr_get_xml_value取得每个属性的值。lr_xml_ extract对于中文值的处理非常特别,返回的值是unicode格式,当使用lr_get_xml_value时会自动转会换为标准编码格式:
lr_xml_get_values("XML={rxmlparam}",
"Query=/book/id",
"ValueParam=id",
LAST);
lr_xml_get_values("XML={rxmlparam}",
"Query=/book/title",
"ValueParam=title",
LAST);
lr_xml_get_values("XML={rxmlparam}",
"Query=/book/author",
"ValueParam=author",
LAST);
lr_xml_get_values("XML={rxmlparam}",
"Query=/book/year",
"ValueParam=year",
LAST);
lr_xml_get_values("XML={rxmlparam}",
"Query=/book/price",
"ValueParam=price",
LAST);
通过这个代码就可以实现从XML中随机记录,再取得随机记录中的各个属性了。
在某些特殊情况我们通过lr_xml_extract()函数取得的某一个节点可能会包含节点属性,当遇到这种情况时这类带节点属性的XML格式就无法直接使用lr_get_xml_value()函数取得的属性值。遇到这种问题我们要再编写一些代码将属性部分清除再重新生成规范的XML,例如:
char *xml;
char temp[1000];
int xmllen;
xml="<mytable msdata:rowOrder=\"16\" diffgr:id=\"mytable17\">
<id>9679</id><chartitle>ABCDE</chartitle><timebody>2010-03-24T01:11:09+08:00</timebody></mytable>";
//xml变量中保存了一个通过lr_xml_extract获得的带属性的XML节点
//这里不能直接对这个XML直接使用lr_get_xml_value取值,会出错
xmllen=strlen(xml);
//<id>前的长度为52,所以这里做一个偏移52长度的操作,适用于定长属性
lr_save_var(xml+52,xmllen-52,0,"newxml");
//重新补充XML根节点开始标记
sprintf(temp,"<mytable>%s",lr_eval_string("{newxml}"));
lr_save_string(temp,"newxml");
lr_xml_get_values("XML={newxml}",
"Query=/mytable/id",
"ValueParam=myid",
LAST);
在上面的这个例子中就会由于mytable后的属性影响XML取值函数的使用(lr_save_var()函数的介绍参考A.7.5节)。那么这里是对该属性做了一个偏移过滤后再补一个新的节点名的方式完成的,当然直接使用C语言的字符数组更为直接(在Vugen中没有Right函数可以直接使用)。
3)lr_xml_find
这个函数可以用来做XML的检查点。我们需要知道在XML中是否存在我们需要的某个值或者某个属性,那么用这个函数会比前面两个函数代价更小。
lr_xml_find("XML={xmlparam}","Query=/bookstore/book/id","Value=No1", LAST);
通过这个查询我们可以检查在xmlparam参数中是否存在/bookstore/book/id这个属性的值为No1的记录,查询的次数作为函数返回。
当服务器的返回为XML结构时,可以考虑使用这个函数来辅助完成手工事务的状态判定(手工事务的概念参考A.9.4节)。
在lr_xml_find中还提供了对于正则表达式的支持,这里把代码修改为:
lr_xml_find("XML={xmlparam}","Query=/bookstore/book/id","Value=No*.","SelectAll=yes","UseRegExp=yes",LAST);
UseRegExp=yes说明在这个函数中我们启用了正则表达式,然后将Value的值从No1修改为No*.,这里的*.是正则表达式,说明匹配任意字符长度。为了更加明显地看到运行效果,这里添加了selectAll=yes,对所有匹配条件进行检查。运行结果为:
Action.c(54): "lr_xml_find" succeeded, 2 matches processed
有两项内容被匹配,因为No1和No2都符合No*.这个正则表达式。这里列出LR支持的正则表达式简表,如表A.14所示。如果不知道自己写的正则表达式是否能够正确匹配,可以使用QTP11内自带的Regular Expression Evaluator进行测试,但是注意QTP11使用的正则表达式比LR11的正则表达式支持的复杂。
表A.14 LR正则表达式表
Meta-character(元字符) Means(含义)
[ 字符集合开始
] 字符集合结束
( ) 括号中的内容为关联需要保存的内容组
^ 匹配输入字符串的开始位置
$ 匹配输入字符串的结束位置
. 匹配除" \n"之外的任何单个字符
? 对前一字符做匹配. 例如, "ab?c" 同时匹配"abc"和"ac".
+ 匹配前面的子表达式一次或多次。例如,"zo+"能匹配"zo"及"zoo",但不能匹配"z"
* 匹配前面的子表达式零次或多次。例如,zo*能匹配"z"及 "zoo"
\ 将下一个字符标记为一个特殊字符、一个原义字符、一个向后引用或一个八进制转义符
| 或条件匹配。例如"(ABC)|(123)" 匹配 "ABC" 或123
除了前面介绍的3个关于XML的函数外,还有lr_xml_delete、lr_xml_insert、lr_xml_ replace、lr_xml_set_values、lr_xml_transform这几个函数,由于篇幅所限和使用频率不高,这几个函数在这里就不详细介绍了,具体用法可参考帮助文档。
fastquery是自动做UTF8解码的,但是query不做,所以在使用这两种查找模式的
时候还需要考虑编码的问题。
在很多时候在地址栏中都会出现时间戳的内容来防止SCRF,那么可以使用这个函数来动态生成web_save_timestamp_param。
5.常见参数和变量的应用总结
1)参数和字符串变量的交换
lr_save_string("hello world","param");//赋值
lr_eval_string("{param}");//取值
2)数字型变量和参数的交换
int x;
x=10;
lr_save_int(x,"param");//整数转参数
x=atoi(lr_eval_string("{param}"));//参数取值转数据类型后成为变量
3)变量存放参数名
char x[100];
x="{param}";
lr_save_string("hello world","param");
lr_eval_string(x); //获得x变量所指向的参数名所对应的值
4)带格式的参数输出
lr_save_string("shanghai","city");
lr_eval_string("welcome to {city}");
版权声明:51Testing软件测试网获作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
相关文章: