Jenkins Groovy按属性选XML节点并添加子节点报错求助
解决XmlSlurper操作XML时的节点查找与子节点添加问题
问题场景
现有如下XML文件:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <testsuites> <testsuite name="xray" tests="2" failure="0" timestamp="2023-07-07T05:25:33.339Z" skipped="0" failure-evaluating="0"> <testcase name="SPT-4323" classname="testim.io.test" time="52.597" ownedBy="Staysure Automation" ownerEmail="automationteam@staysure.co.uk"> </testcase> <testcase name="SPT-4331" classname="testim.io.test" time="20.823" ownedBy="Automation Team" ownerEmail="nipunam@intervest.lk"> </testcase> </testsuite> </testsuites>
需求是选中<testcase name="SPT-4323">节点并添加子节点,但尝试以下两种写法均报错groovy.util.slurpersupport.NodeChildren.find:
xml.testsuite.find{it.@name == 'SPT-4323'}.appendNode( fragmentToAdd ) xml.testsuite.testcase.find{it.@name == 'SPT-4323'}.appendNode( fragmentToAdd )
完整的Jenkins Pipeline阶段代码如下:
stage('Update_XML') { try{ def File = readFile "${env.WORKSPACE}/testim-tests-report.xml" echo "${File}" def xml = new XmlSlurper().parseText(File) def xrayIDs = xml.testsuite.testcase.collect { it.@name } echo "Xray IDs are ${xrayIDs}" def toadd = '''<properties> <property name="test_key" value="SPT-4323" /> </properties>''' fragmentToAdd = new XmlSlurper( false, true ).parseText( toadd ) xml.testsuite.find{it.@name == 'SPT-4323'}.appendNode( fragmentToAdd ) String outxml = groovy.xml.XmlUtil.serialize( xml ) echo "Output XML ${outxml}" } catch(Exception) { build_status = false echo Exception.toString() } };
问题原因
- 第一种写法逻辑错误:
testsuite的name属性是xray,并非目标的SPT-4323,路径和属性匹配完全错误; - 第二种写法存在类型兼容问题:
XmlSlurper解析的节点集合调用find后,直接追加另一个XmlSlurper解析的节点会出现类型不匹配,导致报错; xml.testsuite返回的是NodeChildren类型,直接调用find不符合XmlSlurper的节点操作逻辑。
解决方案
修改后的Pipeline代码如下:
stage('Update_XML') { try{ def fileContent = readFile "${env.WORKSPACE}/testim-tests-report.xml" echo "${fileContent}" def xml = new XmlSlurper().parseText(fileContent) // 准确定位目标testcase节点 def targetTestCase = xml.testsuite.testcase.find { it.@name == 'SPT-4323' } // 用MarkupBuilder构建可兼容的子节点 def writer = new StringWriter() def builder = new groovy.xml.MarkupBuilder(writer) builder.properties { property(name: "test_key", value: "SPT-4323") } def fragmentToAdd = new XmlSlurper().parseText(writer.toString()) // 给目标节点追加子节点 targetTestCase.appendNode(fragmentToAdd) // 序列化输出修改后的XML String outxml = groovy.xml.XmlUtil.serialize(xml) echo "Output XML ${outxml}" // 可选:将修改后的XML写回文件 writeFile file: "${env.WORKSPACE}/updated-testim-tests-report.xml", text: outxml } catch(Exception e) { build_status = false echo e.toString() } };
关键修改点
- 节点定位修正:通过
xml.testsuite.testcase.find { it.@name == 'SPT-4323' }直接匹配目标节点,确保路径和属性完全对应; - 子节点构建优化:改用
MarkupBuilder生成节点内容,再用XmlSlurper解析,避免不同解析实例导致的节点类型不兼容问题; - 异常处理完善:捕获异常时指定变量
e,能输出更详细的错误信息; - 增加写回步骤:可选操作,将修改后的XML保存到文件,满足实际场景的持久化需求。
验证效果
执行修改后的代码后,目标testcase节点会成功添加<properties>子节点,最终XML如下:
<?xml version="1.0" encoding="UTF-8"?> <testsuites> <testsuite name="xray" tests="2" failure="0" timestamp="2023-07-07T05:25:33.339Z" skipped="0" failure-evaluating="0"> <testcase name="SPT-4323" classname="testim.io.test" time="52.597" ownedBy="Staysure Automation" ownerEmail="automationteam@staysure.co.uk"> <properties> <property name="test_key" value="SPT-4323"/> </properties> </testcase> <testcase name="SPT-4331" classname="testim.io.test" time="20.823" ownedBy="Automation Team" ownerEmail="nipunam@intervest.lk"/> </testsuite> </testsuites>
内容的提问来源于stack exchange,提问作者Nipuna Madusanka
相关产品推荐
相关产品推荐

