Will1v
Will1v

Reputation: 196

How to prevent xmllint from removing whitespaces?

Following from this questions, I am now able to update a specific variable in a number of XMLs.

However, they all have a lot (unnecessary) whitespaces and xmllint removes them all. I now have 50 lines modified and that makes it very hard to see the functional difference when looking at git diff. Is there a way for xmllint not to do that and only change the value I'm interested in? (I tried to take a look at xmllint's man but didn't find any option that seemed to that)

Example: Original file:

<target_tags>
    <target_tag name="my_tag1" default="old_value1" />
    <target_tag name="my_tag2" default="old_value2" />
    <target_tag name="my_tag3" default="old_value3" />
</target_tags>

xmllint command:

xmllint --shell /tmp/tmp.xml << EOF
> cd //target_tag[@name="my_tag1"]/@default
> set new_value
> save
> bye
> EOF
/ > default > default > default > 

Modified file:

<target_tags>
    <target_tag name="my_tag1" default="new_value"/>
    <target_tag name="my_tag2" default="old_value2"/>
    <target_tag name="my_tag3" default="old_value3"/>
</target_tags>

Upvotes: 0

Views: 82

Answers (1)

LMC
LMC

Reputation: 12662

A possible solution using xmllint could be to output lines as is until the desired value is found. Then generate a simple xml doc with the line to modify preserving indentation

needle='name="my_tag1"'
new_value="new_value1"
while IFS=$'\n' read line; do
    if ! grep -q "$needle" <<<"$line";then
        # target line not found
        echo "$line"
    else
        temp_file=$(mktemp)
        # save fake xml doc to a temp file
        echo -e "<root>\n$line\n</root>" > $temp_file
        # Change the attribute
        printf "%s\n" "cd //target_tag[@$needle]/@default" "set $new_value" 'save' 'bye' | xmllint --shell $temp_file >/dev/null
        sed -n '3 p' $temp_file
        rm $temp_file
    fi
done < tmp.xml

Only the modified line will be changed

<target_tags>
    <target_tag name="my_tag1" default="new_value"/>
    <target_tag name="my_tag2" default="old_value2" />
    <target_tag name="my_tag3" default="old_value3" />
</target_tags>

Upvotes: 0

Related Questions