1

The loop below finds all of the nodes where the value equals "DOWNLOADING" and grabs the value of the corresponding "bytesdownloaded" node. I was expecting adlBytesDL1[0] to equal 147333120 (from the first matched node); instead, it equals 147333120147329024 (node1 and node2 back to back). I assume I am putting my index in the wrong place, but I cannot figure out where it belongs. Any help is greatly appreciated. I have to use XMLSTARLET with Xpath 1.0.

for ((i=0; i<=(adlCount-1); i++)); do let "j=$i+1" adlBytesDL1[$i]=$(xmlstarlet sel -t -m "//DownloadReport/ActionDownload/Downloads/Status[State='DOWNLOADING']" -v ..//BytesDownloaded['"$j"'] outputlive1.txt) done 

Here is a snippet of my XML file:

<?xml version="1.0" encoding="UTF-8"?> <DownloadReport> <ActionDownload> <ActionID>2284879</ActionID> <State>InProgress</State> <Error></Error> <IsActive>true</IsActive> <Date>Sun, 30 Jun 2024 14:48:39 +0000</Date> <Downloads> <DownloadRequestTarget> <ActionID>2284879</ActionID> <Index>1</Index> <Hashes hashAlgorithm="sha1">cefbabced653b2837ccd4bd906841390b1f87227</Hashes> <Size>1869565324</Size> <URL>http://servername.com/A13_13.26.9U3.zip</URL> </DownloadRequestTarget> <Status> <State>DOWNLOADING</State> <Timestamp>Sun, 30 Jun 2024 14:48:39 +0000</Timestamp> <RetryCount>0</RetryCount> </Status> <Available>false</Available> <BytesDownloaded>147333120</BytesDownloaded> <TotalBytes>1869565324</TotalBytes> <RetryLimit>5</RetryLimit> </Downloads> <Downloads> <DownloadRequestTarget> <ActionID>2284879</ActionID> <Index>2</Index> <Hashes hashAlgorithm="sha1">7e90e741c6ffd3476bdbae0262ff5a6aad49b925</Hashes> <Size>1877973677</Size> <URL>http://servername.com/A13_13.29.10U0.zip</URL> </DownloadRequestTarget> <Status> <State>DOWNLOADING</State> <Timestamp>Sun, 30 Jun 2024 14:48:39 +0000</Timestamp> <RetryCount>0</RetryCount> </Status> <Available>false</Available> <BytesDownloaded>147329024</BytesDownloaded> <TotalBytes>1877973677</TotalBytes> <RetryLimit>5</RetryLimit> </Downloads> </ActionDownload> </DownloadReport> 
2
  • Try changing ..//BytesDownloaded['"$j"'] to ..//BytesDownloaded["$j"], "..//BytesDownloaded[$j]" or "..//BytesDownloaded['$j']".CommentedAug 5, 2024 at 22:10
  • Thanks G-MAN. I tried all of those variations but non worked.
    –  webbytr
    CommentedAug 6, 2024 at 1:17

1 Answer 1

1

Sounds like you just need:

set -o noglob adlBytesDL1=( $(xmlstarlet sel -t -v '/DownloadReport/ActionDownload/Downloads[Status/State="DOWNLOADING"]/BytesDownloaded' -n file.xml) ) 

(assuming $IFS has not been modified from its default value).

The set -o noglob is to avoid the DoS vulnerability if BytesDownloaded can't be guaranteed to be just a number. In any case, the splitting relies on those being just numbers.

Note the -n to add a newline after each value.

Your approach doesn't work as it gets the jthBytesDownloaded of the matching Downloadss, while you want the BytesDownloaded of the jth matching Downloads, which should be something like:

/DownloadReport/ActionDownload/Downloads[Status/State='DOWNLOADING'][$j]/BytesDownloaded 

You also had left the [, ] which are globbing operators in most shells unquoted.

Feels wrong from a style PoV to have a mix of ((...)) and let. You could have done:

for (( i = 1; i <= adlCount; i++ )); do adlBytesDL1[i-1]=$( xmlstarlet sel -t -v "/DownloadReport/ActionDownload/Downloads[Status/State='DOWNLOADING'][$i]/BytesDownloaded" file.xml ) done 

But it's quite inefficient to run one xmlstarlet for each value when you can get all the values at once.

0

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.