0

I am using this XML file: https://github.com/apache/ranger/blob/master/ugsync/src/test/resources/ranger-ugsync-site.xml

Now, I have to update the value of the following property to false.

<property>
  <name>ranger.usersync.group.usermapsyncenabled</name>
  <value>true</value>
</property>

To update the value of property in the XML to false, I am using the below command in the bash script to get the updates done.

tag1=<name>ranger.usersync.group.usermapsyncenabled</name>
file=xml_file.xml
temporary=temp.xml

grep -A1 $tag1 $file | grep -v $tag1 | sed -e "s/^.*<value>/<value/" | sed -e "s/<value>true<\/value>/<value>false<\/value>/g" $file > $temporary

Problem: The script is updating all the other attributes in the file with value true to false. I just need to update the value of this attribute and not others. Input/help is appreciated. Thanks!

yguw
  • 856
  • 6
  • 12
  • 32
  • Hmm. I'm tempted to call this duplicative of [parsing xml and replacing specific tags shell script](https://stackoverflow.com/questions/43967407/parsing-xml-to-and-replacing-specific-tags-shell-script), which includes an XMLLint approach in the answers as well. Ideally, would like to find a duplicative question with a Python-wrapped-in-a-shell-function answer, since that's likely to be useful to folks who for whatever reason can't install XMLStarlet and who don't have a new enough XMLLint. – Charles Duffy Feb 25 '18 at 19:11
  • ...to be clear, by the way -- XML-aware answers are *strongly* preferred for this class of question because standard text-based tools *simply don't, and can't, understand XML*. You can't teach `grep` and `sed` to ignore XML comments and CDATA sections, *and* to read `xmlns` tags to figure out the current namespace, and to read DTDs and understand any macros they contain, etc. – Charles Duffy Feb 25 '18 at 19:14

1 Answers1

4

Using XMLStarlet:

xmlstarlet ed \
  -u "//property[name='ranger.usersync.group.usermapsyncenabled']/value" \
  -v false \
  <in.xml >out.xml

The XPath expression used to determine what to change ensures that we only modify a value that is under a property with the appropriate name.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • the problem using XMLStarlet is that it disrupts the formatting and also changes the line to . Hope that is going to be fine? I am planning to use this script in a Dockerfile so that it can do the updates when I run the dockerfile and so I was looking more for sed or grep steps. Sorry, kinda new to scripting and hence looking for the right answers. – yguw Feb 25 '18 at 19:28
  • @yguw, the values are semantically equivalent to each other, which is to say that any compliant XML parser will treat both documents as equal except for the desired change. – Charles Duffy Feb 25 '18 at 19:29
  • 1
    See my comments on the question speaking to why `sed` and `grep` are *not* the right answer for any kind of XML-manipulation task. – Charles Duffy Feb 25 '18 at 19:30
  • 1
    Also, note the `-S` and `-P` arguments to `xmlstarlet ed` to preserve original whitespace. – Charles Duffy Feb 25 '18 at 19:31
  • 1
    (BTW, if you want to prevent spurious changes to the text of your XML documents when modifying their content, consider keeping them in canonicalized form; see the [XML C14N standard](https://www.w3.org/TR/xml-c14n11/) -- any XML processor that supports the standard will be able to take a canonicalized document as input and emit byte-for-byte-identical output except for the actual desired change (when told to write canonicalized output). – Charles Duffy Feb 25 '18 at 20:10
  • I see that it works, but I'm confused by the `@name` part. I thought `@` was for accessing attributes. – Cole Tierney Feb 26 '18 at 00:49
  • @ColeTierney, ...it is, and that was a bug in my answer. Thank you for the catch. – Charles Duffy Feb 26 '18 at 15:51