NuCradle
NuCradle

Reputation: 705

How to Get Two Separate Siblings with XPath

I am trying to invoke Jenkins XML API to retrieve specific set of information from its REST endpoint (... indicates that there are similar sibling elements in the content but excluded for brevity):

<workflowRun _class="org.jenkinsci.plugins.workflow.job.WorkflowRun">
   <action _class="hudson.model.CauseAction">
      <cause _class="hudson.triggers.TimerTrigger$TimerTriggerCause">
         <shortDescription>Started by timer</shortDescription>
      </cause>
   </action>
   <action _class="hudson.model.ParametersAction">
      <parameter _class="hudson.model.StringParameterValue">
         <name>projectName</name>
         <value>My-Proj</value>
      </parameter>
      <parameter _class="hudson.model.StringParameterValue">
         <name>NodeParam</name>
         <value>UY-DO1</value>
      </parameter>
      ...
   </action>
   <action/>
   <action/>
   <action/>
   <action/>
   <action _class="org.jenkinsci.plugins.workflow.cps.EnvActionImpl"/>
   <action/>
   <action _class="hudson.tasks.junit.TestResultAction">
      <failCount>21</failCount>
      <skipCount>6</skipCount>
      <totalCount>223</totalCount>
      <urlName>myReport</urlName>
   </action>
   <action/>
   <action/>
   <action/>
   <action _class="org.jenkinsci.plugins.workflow.job.views.FlowGraphAction"/>
   <action/>
   <action/>
   <building>false</building>
   ...
   <result>FAILURE</result>
   <timestamp>1553145960340</timestamp>
   ...
</workflowRun>

I am interested in obtaining the following information only:

   <action _class="hudson.tasks.junit.TestResultAction">
      <failCount>21</failCount>
      <skipCount>6</skipCount>
      <totalCount>223</totalCount>
      <urlName>myReport</urlName>
   </action>       
   <timestamp>1553145960340</timestamp>

However, I cannot find an XPath command to grab all this data in one go. I can run two separate calls to retrieve the needed information but that requires two separate server trips. I was wondering if there is an XPath command I can use to retrieve the targeted <action> and <timestamp> in one go:

https://jenkins_host/job/MyApp/job/Some_Jenkins_Job/lastCompletedBuild/api/xml?xpath=/workflowRun/action[@_class='hudson.tasks.junit.TestResultAction']

Which gets us:

   <action _class="hudson.tasks.junit.TestResultAction">
      <failCount>21</failCount>
      <skipCount>6</skipCount>
      <totalCount>223</totalCount>
      <urlName>myReport</urlName>
   </action>  

and timestamp separately (note a switch from xpath to tree):

https://jenkins_host/job/MyApp/job/Some_Jenkins_Job/lastCompletedBuild/api/xml?tree=timestamp

with the outcome of:

<workflowRun _class="org.jenkinsci.plugins.workflow.job.WorkflowRun">
   <timestamp>1553145960340</timestamp>
</workflowRun>

I have tried to use a combination of tree and xpath but getting errors:

https://jenkins_host/job/MyApp/job/Some_Jenkins_Job/lastCompletedBuild/api/xml?tree=timestamp&xpath=/workflowRun/action[@_class='hudson.tasks.junit.TestResultAction']

Seems like they can't be mixed up. I even tried using this at no avail:

xml?xpath=/workflowRun/action[@_class='hudson.tasks.junit.TestResultAction']&/workflowRun/timestamp

or

xml?xpath=/workflowRun/action[@_class='hudson.tasks.junit.TestResultAction']&xpath=/workflowRun/timestamp

Any idea how I can get both set of data with a single XPath?

Upvotes: 0

Views: 258

Answers (2)

Alejandro
Alejandro

Reputation: 1882

The next one is a perfectly valid XPath 1.0 expression, but I don't know whether your REST endpoint can or cannot parse it...

/workflowRun
   /action[@_class='hudson.tasks.junit.TestResultAction']
|/workflowRun
   /action[@_class='hudson.tasks.junit.TestResultAction']
      /following-sibling::timestamp[1]

Or without union (forced to use the Kaysian method):

/workflowRun
   /*[self::action/@_class='hudson.tasks.junit.TestResultAction' or
      self::timestamp[
         count(.|../action[@_class='hudson.tasks.junit.TestResultAction']/following-sibling::timestamp[1]) 
         = count(../action[@_class='hudson.tasks.junit.TestResultAction']/following-sibling::timestamp[1])
     ]]

The key in both is to select the reference element (the action) and then following sibling timestamp and not just every timestamp.

Upvotes: 1

fpsthirty
fpsthirty

Reputation: 185

As an option, union grouped expressions through by one of operators: | or or. Choose one of this solutions:

  1. |-operator:

(//action[@_class='hudson.tasks.junit.TestResultAction']/descendant-or-self::*)|//timestamp

  1. or-operator:

    //*[self::action[@_class='hudson.tasks.junit.TestResultAction'] or self::timestamp]/descendant-or-self::*

Upvotes: 0

Related Questions