Search code examples
xmlxpathattributesxmlstarlet

xmlstarlet: create an attribute if it does not exist and edit it otherwise


I would like to use xmlstarlet to find the element of an xml file which contains the attribute inkscape:label="L2" and set the its attribute "style" to the value "display.inline". The difficulty is that the attribute "style" may or may not already be defined.

I am currently using this command:

xmlstarlet edit --inplace --update "//*[@inkscape:label=\"L2\"]/@style" --value "display:inline" ex.svg 

It will work if the attribute style is already defined

// It works on this
<g inkscape:groupmode="layer"
 id="layer2"
 inkscape:label="L2"
 style="display:none">

but it will not work otherwise:

// Does not work
<g inkscape:groupmode="layer"
 id="layer2"
 inkscape:label="L2">

I also defined a command which enables to add the desired attribute:

xmlstarlet ed --insert "//*[@inkscape:label=\"L2\"]" --type attr -n style -v "display:inline" ex.svg > output.svg

Unfortunately, if the attribute already exists, a second one will be added:

// The element now contains two attributes style
<g inkscape:groupmode="layer"
 id="layer2" 
 inkscape:label="L2" 
 style="display:none" 
 style="display:inline">

Is there a way to create the attribute if it does not exist and to edit it otherwise?


Solution

  • You can use both the --update and --insert, but only insert when the element does not have a style attribute (not(@style)).

    Example:

    xmlstarlet edit --inplace --update "//*[@inkscape:label=\"L2\"]/@style" --value "display:inline" --insert "//*[@inkscape:label=\"L2\"][not(@style)]" --type attr -n style -v "display:inline" ex.svg