12-22-2021 08:48 PM - edited 01-28-2022 06:27 PM
xpath is not super intuitive. Maybe I can clear up 1 tiny little thing here...
First, a resource I go back to again & again: Xpath cheatsheet
Second, xpath is a querying language. It can look complicated, but, a way of simplifying it is to think of the syntax as an analogy: exposing xml data as a "file system" & the thing you want to "get" as a "file". Your xpath query is the "file path". Elements, in the analogy, are "folders" with stuff in them: one thing, many things, etc. E.g., you might want all IDs for some object in Jamf Pro (let's say policies) so maybe you tried:
curl -Ss -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/policies" | xmllint --xpath "//id" - | tr '</id>' '\n'
Not great because you are stripping the xml data structure & tr often outputs strange results.
Then maybe you looked at the xpath cheat sheet or took a Jamf course & discovered the magical text() command which strips xml tags!
curl -Ss -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/policies" | xmllint --xpath "//id/text()"
But you get something like:
11971190119211931194119512676531279103458411133271180111483812706051283583632...
Why? Because xpath is simply doing what you asked: returning data where the tag name is equal to "id". Even though we thought we would get the "items" in this "file path", we did & we didn't.
So, then you tried this: Jamf API xmllint --xpath Question - smooshed output problem solved, but, still stripping the data structure.
Don't be sad. xpath doesn't iterate for you but it does understand the index of each member in each element in the data. The xpath command needed to get delimited output is (weirdly? not weirdly?) concat
apidata=$(curl -sS -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/policies")
arrsize=$(echo "$apidata" | xmllint --xpath "//size/text()" -)
for ((i=0;i<=$arrsize;i++))
{
echo "$apidata" | xmllint --xpath "concat(//policy[$i]/id/text(),' ')" -
}
Output:
1197 1190 119 211 931 1941 195 1267 653 12...
The result is a space-delimited set of object IDs. Now you can generalize this into a function for getting the IDs of any Jamf Pro object:
apiuser='someuser'
apipswd='password'
jamfurl='https://somejamfurl.whatever:8443/JSSResource'
jamfids()
{
apidata=$(curl -sS -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/$1")
arrsize=$(echo "$apidata" | xmllint --xpath "//size/text()" -)
for ((i=0;i<=$arrsize;i++)) { echo "$apidata" | xmllint --xpath "concat(//$2[$i]/id/text(),' ')" - ; }
}
policy_ids=($(jamfids policies policy))
configuration_profile_ids=($(jamfids osxconfigurationprofiles os_x_configuration_profile))
etc.
Enjoy!
Solved! Go to Solution.
01-02-2023 10:43 AM - edited 01-02-2023 01:19 PM
Hi Armin -
It looks like the xmllint version has indeed been updated:
Monterey -
% sw_vers -productVersion
12.6.2
% xmllint --version
xmllint: using libxml version 20904
Ventura -
% sw_vers -productVersion
13.1
% xmllint --version
xmllint: using libxml version 20913
The function for getting ids above still works the same (just tried it on Ventura), but, it's unnecessary on macOS 13 & later because xmllint is no longer dumb about output & handles the counting + looping + concatenating behavior for you. This is a good thing!
So, for Monterey & prior (or in Ventura if you don't feel like changing anything...):
apiuser='someuser'
apipswd='password'
jamfurl='https://somejamfurl.whatever:8443/JSSResource'
jamfids()
{
apidata=$(curl -LSs -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/$1")
arrsize=$(echo "$apidata" | xmllint --xpath "//size/text()" -)
for ((i=0;i<=$arrsize;i++)) { echo "$apidata" | xmllint --xpath "concat(//$2[$i]/id/text(),' ')" - ; }
}
policy_ids=($(jamfids policies policy))
configuration_profile_ids=($(jamfids osxconfigurationprofiles os_x_configuration_profile))
For Ventura & beyond I still like the idea of a (simplified) generalized function for getting object ids:
jamfids()
{
curl -LSs -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/$1" | xmllint --xpath "//$2/id/text()" -
}
Thanks.
Posted on 01-02-2023 05:47 AM
There seems to be a change to the `xmllint` command'd behavior in Ventura. Now this
```
echo $xml | xmllint --xpath '/policies/policy/id/text()' -
```
returns a new line separated list of all the ids
01-02-2023 10:43 AM - edited 01-02-2023 01:19 PM
Hi Armin -
It looks like the xmllint version has indeed been updated:
Monterey -
% sw_vers -productVersion
12.6.2
% xmllint --version
xmllint: using libxml version 20904
Ventura -
% sw_vers -productVersion
13.1
% xmllint --version
xmllint: using libxml version 20913
The function for getting ids above still works the same (just tried it on Ventura), but, it's unnecessary on macOS 13 & later because xmllint is no longer dumb about output & handles the counting + looping + concatenating behavior for you. This is a good thing!
So, for Monterey & prior (or in Ventura if you don't feel like changing anything...):
apiuser='someuser'
apipswd='password'
jamfurl='https://somejamfurl.whatever:8443/JSSResource'
jamfids()
{
apidata=$(curl -LSs -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/$1")
arrsize=$(echo "$apidata" | xmllint --xpath "//size/text()" -)
for ((i=0;i<=$arrsize;i++)) { echo "$apidata" | xmllint --xpath "concat(//$2[$i]/id/text(),' ')" - ; }
}
policy_ids=($(jamfids policies policy))
configuration_profile_ids=($(jamfids osxconfigurationprofiles os_x_configuration_profile))
For Ventura & beyond I still like the idea of a (simplified) generalized function for getting object ids:
jamfids()
{
curl -LSs -X GET -H 'accept: application/xml' -u "$apiuser:$apipswd" "$jamfurl/$1" | xmllint --xpath "//$2/id/text()" -
}
Thanks.