Search code examples
xmlshellxpathxmllint

Unable to Parse XML in Shell


SO, below is my xml I am trying to parse. First I used XmlSlurper in my Jnekinsfile, parsing was easy but I faced performace issues in pipeline. Now I am using XMLlint, but it isnt as easy as XmlSlurper :(

<metadata modelVersion="1.1.0">
  <groupId>com.test.test.test</groupId>
  <artifactId>myApp-ear</artifactId>
  <version>4.0.0-10-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <timestamp>20200803.052228</timestamp>
      <buildNumber>3</buildNumber>
    </snapshot>
    <lastUpdated>20200803052228</lastUpdated>
    <snapshotVersions>
      <snapshotVersion>
        <extension>ear</extension>
        <value>4.0.0-10-20200803.052228-3</value>
        <updated>20200803052228</updated>
      </snapshotVersion>
      <snapshotVersion>
        <extension>pom</extension>
        <value>4.0.0-10-20200803.052228-3</value>
        <updated>20200803052228</updated>
      </snapshotVersion>
    </snapshotVersions>
  </versioning>
</metadata>

I want to parse and fetch value of <value>4.0.0-10-20200803.052228-3</value> from <snapshotVersion> with <extension> type ear.

This is my code snippet,

 $(xmllint --xpath "/metadata/artifactId/text()"
 metadataFile)-$(xmllint --xpath
 "/metadata/versioning/snapshotVersions[0]/value/text()"
 metadataFile).$(xmllint --xpath
 "/metadata/versioning/snapshotVersions[0]/extension/text()"
 metadataFile)

Output:

++ xmllint --xpath '/metadata/artifactId/text()' metadataFile ++ xmllint --xpath '/metadata/versioning/snapshotVersions[0]/value/text()' metadataFile XPath set is empty ++ xmllint --xpath '/metadata/versioning/snapshotVersions[0]/extension/text()' metadataFile XPath set is empty

Kindly help.

Thanks in Advance :)


Solution

  • Faced with an error like that, I usually start trying to shorten my xpath expression until I find out where I'm getting unexpected data. Your complete expressions is:

    /metadata/versioning/snapshotVersions[0]/value/text()
    

    That's returning an empty set. If we try instead:

    /metadata/versioning/snapshotVersions
    

    We see this returns:

    <snapshotVersions>
          <snapshotVersion>
            <extension>ear</extension>
            <value>4.0.0-10-20200803.052228-3</value>
            <updated>20200803052228</updated>
          </snapshotVersion>
          <snapshotVersion>
            <extension>pom</extension>
            <value>4.0.0-10-20200803.052228-3</value>
            <updated>20200803052228</updated>
          </snapshotVersion>
        </snapshotVersions>
    

    Great! But if we add [0] to that, we get the empty set again:

    $ xmllint --xpath '/metadata/versioning/snapshotVersions[0]' metadata.xml
    XPath set is empty
    

    There are two reasons for that:

    1. You need to apply the [n] operator to the elements that make up the list (so, snapshotVersion, not snapshotVersions), and

    2. Xpath starts enumerating elements from 1 rather than 0.

    So this seems to do what you want:

    $ xmllint --xpath '/metadata/versioning/snapshotVersions/snapshotVersion[1]/value/text()' metadata.xml
    4.0.0-10-20200803.052228-3