Home > Net >  Add property to xml using xmlstarlet
Add property to xml using xmlstarlet

Time:02-01

I have the following base XML

<hibernate-configuration>
  <session-factory>
    <mapping />
  </session-factory>
</hibernate-configuration>

That same base XML can contain some properties or not, for example:

<hibernate-configuration>
  <session-factory>
    <mapping />
    <property name="driver_class">some-class</property>
    <property name="driver_dialect">some-dialect</property>
  </session-factory>
</hibernate-configuration>


Now i need to use xmlstarlet to insert those properties if they do not exist or update those values if they do exist without creating any duplicates. I know how to update and also know how to insert, but since i do not know in advance if those properties exist or not I have no idea how i can do that.

What would be the correct way of doing that ?

CodePudding user response:

Once you add property, insert the name attribute (separately):

xmlstarlet ed -s "/hibernate-configuration/session-factory" -t elem -name "property" -v "com.mysql.jdbc.Driver" -i "//property" -type attr -name "name" -v "driver_class" input.xml

CodePudding user response:

I don't see any "insert or update", or any xmlstarlet subcommands that are conditionals. Presumably you want to use xmlstarlet so you don't have to write XSLT.

This is the best I could come up with: the sel subcommand returns a non-zero exit status if the xpath does not exist in the document.

#!/bin/bash

xpath_root="/hibernate-configuration/session-factory"

set_property() {
    local file=$1 name=$2 value=$3
    local xpath="$xpath_root/property[@name = '$name']"
    local tmpfile=$(mktemp)

    if xmlstarlet sel -t -v "$xpath" "$file" >/dev/null
    then
        # property exists, alter it
        xmlstarlet ed -O -u "$xpath" -v "$value" "$file"

    else
        # property does not exists, add it
        xmlstarlet ed -O \
            -s "$xpath_root" -t elem -n "property" -v "$value" \
            -a "$xpath_root/property[not(@name)]" -t attr -n "name" -v "$name" \
            "$file"

    fi > "$tmpfile" && mv "$tmpfile" "$file"
}

for file in base1.xml base2.xml; do
    cp "$file" "$file.bak"
    set_property "$file" driver_class "new class"
    set_property "$file" driver_dialect "new dialect"
done

After running the script

$ diff base1.xml{.bak,}
3a4,5
>     <property name="driver_class">new class</property>
>     <property name="driver_dialect">new dialect</property>

and

$ diff base2.xml{.bak,}
4,5c4,5
<     <property name="driver_class">some-class</property>
<     <property name="driver_dialect">some-dialect</property>
---
>     <property name="driver_class">new class</property>
>     <property name="driver_dialect">new dialect</property>
  • Related