1

We have a policy.xml file as below and need to insert a string like below under each session of the xml file under (inbound or backend or outbound) just under <base /> depending on the condition from shell script,

Sample policy.xml

<policies>
    <inbound>
      <base />
    </inbound>
    <backend>
      <base />
    </backend>
    <outbound>
      <base />
    </outbound>
    <on-error>
      <base />
    </on-error>
</policies>

String want to add

<rate-limit-by-key calls="xx" renewal-period="xx" counter-key="@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)" />`

we tried to use xmlstarlet for this purpose, but couldn't achieve what we are looking for

for example to import the string under [policies/inbound/base]

xmlstarlet edit --subnode "//policies/inbound/" xxxxxxxxxxxxxxxx policy.xml > custompolicy.xml

our Script

#!/bin/bash
################Variables##################
source parse_yaml.sh
eval $(parse_yaml input2.yaml policy)

ipfilter="<rate-limit-by-key calls="xxx" renewal-period="xx" counter-key="@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)" />"

echo ".............Eval Result..............................."
for f in $policy_ ; do eval echo \$f \$${f}_ ; done
echo "............Eval Result................................"
echo " ********policy is ************ "

for f in $policy_ ; do
  if [[ $(eval echo \$${f}_name) == "ipfilter" ]]; then
    echo " given policy name is ipfilter "
    if [[ $(eval echo \$${f}_scope) == "api" ]]; then
    echo "decided the scope of Ipfilter policy as api "
    fi
    for g in $(eval echo \$${f}_apis_); do
     echo " this policy will be applied to apis, $g"
     for h in $(eval echo \$${g}_session_); do
     echo " this policy will be applied to api, $g under sesion $h "
     if [[ $(eval echo \$${g}_session_) == "inbound" ]]; then
     echo "add the add Ipfilter string to the inbound session of xml"
     xmlstarlet edit --subnode "//policies/ibound/" xxxxxxxxxxxxxxxx policy.xml > custompolicy.xml
     fi
     done

Expected Output for the custom policy file generated for the condition succeeded for "inbound"

<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>
2
  • It is better to use XSLT for such tasks. Commented Feb 18, 2024 at 17:27
  • Any example for this to get it done ? Commented Feb 18, 2024 at 18:38

1 Answer 1

1

Here it is via XSLT.

The XSLT is using a so called Identity Transform pattern.

Also will this make a duplicate entry, if the string is already present?

XPath predicate [not(rate-limit-by-key)] is preventing duplicate entry.

You just need to know how to launch XSLT transformation in your environment.

XmlStarlet Reference - Transforming XML documents

input XML

<policies>
    <inbound>
        <base/>
    </inbound>
    <backend>
        <base/>
    </backend>
    <outbound>
        <base/>
    </outbound>
    <on-error>
        <base/>
    </on-error>
</policies>

XSLT 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" omit-xml-declaration="yes"
               encoding="UTF-8" indent="yes"/>
   <xsl:strip-space elements="*"/>

    <!--Identity transform-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="inbound[not(rate-limit-by-key)] | backend[not(rate-limit-by-key)] | outbound[not(rate-limit-by-key)]">
        <xsl:copy>
            <xsl:copy-of select="*"/>
            <rate-limit-by-key calls="xx" renewal-period="xx" counter-key='@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)' />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Output XML

<policies>
  <inbound>
    <base/>
    <rate-limit-by-key calls="xx" renewal-period="xx" counter-key='@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)'/>
  </inbound>
  <backend>
    <base/>
    <rate-limit-by-key calls="xx" renewal-period="xx" counter-key='@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)'/>
  </backend>
  <outbound>
    <base/>
    <rate-limit-by-key calls="xx" renewal-period="xx" counter-key='@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)'/>
  </outbound>
  <on-error>
    <base/>
  </on-error>
</policies>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, But I feel its difficult to use this in shell script where i have to customize the "template match" with different conditions which is getting succeeded. Also will this make a duplicate entry, if the string is already present ?
I updated the answer with the XPath predicate to prevent duplicate entries. Check it out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.