问题
I have an XML file which I'd like to use as input for a pipeline script. Problem is the XMLParser isn't serializable so I put it in a NonCPS function, but I lost the Node object because of that.
This is the pipeline script:
def buildPlanPath = 'C:\\buildPlan_test.xml'
@NonCPS
groovy.util.Node getBuildPlan(path) {
new XmlParser().parseText(readFile(path))
}
node {
//def buildPlan = new XmlParser().parseText(readFile(buildPlanPath))
groovy.util.Node buildPlan = getBuildPlan(buildPlanPath)
println buildPlan.getClass()
println buildPlan
println buildPlan.branch
}
This is an input sample:
<branch name='mybranch'>
<stage>
<job name='job11' />
<job name='job12' />
</stage>
<stage>
<job name='job21' />
<job name='job22' />
<job name='job23' />
</stage>
<stage>
<job name='job31' />
</stage>
</branch>
This is the result:
Started by user admin
[Pipeline] node
Running on master in C:\Jenkins\workspace\pipeline-develop
[Pipeline] {
[Pipeline] readFile
[Pipeline] echo
class java.lang.String
[Pipeline] echo
<branch name='mybranch'>
<stage>
<job name='job11' />
<job name='job12' />
</stage>
<stage>
<job name='job21' />
<job name='job22' />
<job name='job23' />
</stage>
<stage>
<job name='job31' />
</stage>
</branch>
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: branch for class: java.lang.String
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:458)
at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.getProperty(DefaultInvoker.java:25)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:17)
at WorkflowScript.run(WorkflowScript:16)
at ___cps.transform___(Native Method)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:62)
at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:54)
at sun.reflect.GeneratedMethodAccessor327.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:58)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:154)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:276)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$000(CpsThreadGroup.java:78)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:185)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:183)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:47)
at java.util.concurrent.FutureTask.run(Unknown Source)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Finished: FAILURE
I'm using Jenkins 2.7 with pipeline 2.1, which are currently the latest.
回答1:
You could use XmlSlurper, it works for me.
def xmlText = new XmlSlurper().parse(MyURL)
xmlText.data.artifact.each {******
回答2:
As branch is the root element, you don't need to explicitly specify it when accessing your parsed nodes
Try changing
println buildPlan.branch
To
println buildPlan.stage
To print out the stage nodes
回答3:
A @NonCPS
method should only accept or return Serializable
types. Try returning .branch
from the method.
回答4:
In the end I think my approach was wrong: I decided to convert the XML file into a separate groovy script and load it within the pipeline
Update: Recently people started editing my answer for clarity, but the fact is that I just ditched storing my configuration in XML files and opted for groovy scripts, which gave me more flexibility. I understand it may not be a common practice, but it suits my needs.
For example - instead of:
config.xml:
<settings>
<floopi>2</floopi>
</settings>
I used:
config.groovy:
def call() {[
floopi: 2
]}
return this
And in the pipeline script:
stage('init') {
def settings = load('config.groovy')()
echo "floopi: ${settings.floopi}"
}
I hope that's a better answer :)
来源:https://stackoverflow.com/questions/37643447/parsing-an-xml-file-within-a-jenkins-pipeline