xmlubuntuxml-namespacesxmlstarlet

xmlstarlet is unable to add subnode when more than one xmlns attribute is present in the first element


I have an xml file test.gpx:

cat test.gpx

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1">
  <trk>
    <name>Name 1</name>
    <desc>Description 1</desc>
  </trk>
  <trk>
    <name>Name 2</name>
    <desc>Description 2</desc>
  </trk>
</gpx>

xmlstartlet is not able to perform successfully when trying to insert a subnode in this file:

xmlstarlet edit --subnode "/gpx/trk" --type  elem -n "new" -v "Hello World!" test.gpx

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1">
  <trk>
    <name>Name 1</name>
    <desc>Description 1</desc>
  </trk>
  <trk>
    <name>Name 2</name>
    <desc>Description 2</desc>
  </trk>
</gpx>

Whereas with only one attribute in the first gpx element, it works:

xmlstarlet edit --subnode "/gpx/trk" --type  elem -n "new" -v "Hello World!" test.gpx

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <trk>
    <name>Name 1</name>
    <desc>Description 1</desc>
    <new>Hello World!</new>
  </trk>
  <trk>
    <name>Name 2</name>
    <desc>Description 2</desc>
    <new>Hello World!</new>
  </trk>
</gpx>

Hence my question: how could I succeed with the original file, having more than one attribute in its first gpx element?

Version info:

xmlstarlet --version
1.6.1
compiled against libxml2 2.9.10, linked with 20913
compiled against libxslt 1.1.34, linked with 10134

On Ubuntu 22.04.


Solution

  • The attributes your are dealing with aren't just garden variety attributes - they are namespaces and have to be taken into account accordingly. Since you have a default namespace in your first (but not second) file, you can deal with it in one of two ways.

    The long, explicit way:

    xmlstarlet ed -N x=http://www.topografix.com/GPX/1/1 --subnode "/x:gpx/x:trk" --type  elem -n "new" -v "Hello World!" test.gpx
    

    or the shorter:

    xmlstarlet ed  --subnode "/_:gpx/_:trk" --type  elem -n "new" -v "Hello World!" test.gpx
    

    Either one should give you your expected output.