The parse yaml utility which I used in my shell script produces variables as below by eval command
policy1_name='ipfilter'
policy1_scope='api'
policy1_apiname='apiname'
policy1_inboundsession='rate-limit-by-key calls="25" renewal-period="60"
counter-key="@\(Regex.Match\(context.xxx.xxxx.GetValueOrDefault\("X-xxxxxxx-For",""\), @"^[.0-9]*"\)?.Value\)'
policy1_outboundsession_ipAddressesFrom='1xxxxxxxx'
policy1_outboundsession_ipAddressesTo='1yyyyyyy'
policy1_=' policy1_name policy1_scope policy1_apiname policy1_inboundsession policy1_outboundsession'
policy1_outboundsession_=' policy1_outboundsession_ipAddressesFrom policy1_outboundsession_ipAddressesTo'
policy_=' policy1'
I know, I can use xmlstarlet to create element inside my outputpolicy.xml file as given below.
for g in $(eval echo \$${f}_apiname); do
echo " this policy will be applied to apis,$(eval echo \$${f}_apiname)"
done
if [ -z "$(eval echo \$${f}_inboundsession_)" ]; then
echo 'the inbound session is not present'
else
echo 'the inbound session is present and append the policy settings to inbound'
xmlstarlet ed -O -s '//inbound' -t elem -n rate-limit-by-key -i '//inbound/rate-limit-by-key' -t attr -n calls -v xx -i '//inbound/rate-limit-by-key' -t attr -n renewal-period -v yy -i '//inbound/rate-limit-by-key' -t attr -n counter-key -v '@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)' policy.xml > io_ou_ipfilter.xml
but what I am looking is use xmlstarlet in my script to read the output of the above script variable "$(eval echo $${f}inboundsession) and insert the given string under inbound session of the below policy.xml file if the string is not preset.
Expected Output
<policies>
<inbound>
<base />
<rate-limit-by-key calls="xxx" renewal-period="xx" counter-key="@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Here's how you could add the
rate-limit-by-keynode, or not if it exists.where:
-a …(aka--append) adds a following-sibling node, it executes only if its argument matches an existing node and so the XPath predicate (not(following-sibling::rate-limit-by-key)) specifies an add-if-not-exists condition-a …matches nothing then$prev[] will match nothing and this will nullify the following$prev-dependent-s …(aka--subnode) options-v(aka--value) options here use string literals but they can be changed to pull in a shell variable (-v "${somevar}") or the result of a command substitution (-v "$(somecmd)")[] In an
xmlstarlet editcommand--vardefines a named variable, and the back reference$prevvariable (aka$xstar:prev) refers to the node(s) created by the most recent-s,-i, or-aoption which all define or redefine it (seexmlstarlet.txtfor a few examples of--varand$prev).Note that the expected output you posted is not XML as it contains quote characters in an attribute value which an XML serializer will likely output as
".Given this input file,
the command above produces,