How to declare XPath namespaces in xmlstarlet?

I am new to xmlstarlet so hoping this answer is a simple one.

I am writing a script to modify Inkscape SVG files from the command line. I chose the tool xmlstarlet.

After testing the command syntax on test files, I am having trouble on the real SVG files. I think the use of namespaces is throwing me off.

Example file:

<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) -->     <svg    xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"    xmlns:dc="http://purl.org/dc/elements/1.1/"    xmlns:cc="http://creativecommons.org/ns#"    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"    xmlns:svg="http://www.w3.org/2000/svg"    xmlns="http://www.w3.org/2000/svg"    xmlns:xlink="http://www.w3.org/1999/xlink"    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"    width="603"    height="1000"    viewBox="0 0 159.54375 264.58334"    version="1.1"    id="svg8"    inkscape:version="0.92.1 r"    sodipodi:docname="test.svg"    inkscape:export-filename="/home/user/dev/inkscape/test/1.png"    inkscape:export-xdpi="96"    inkscape:export-ydpi="96">   <defs      id="defs2">     <linearGradient        inkscape:collect="always"        id="linearGradient6204">       <stop          style="stop-color:#8f1a22;stop-opacity:1;"          offset="0"          id="stop6200" />       <stop          style="stop-color:#8f1a22;stop-opacity:0;"          offset="1"          id="stop6202" />     </linearGradient>   </defs> </svg> 

I want to change Gradient6204 to Gradient9999.

I wrote this command, which does not work (just returns the original file).

xmlstarlet ed -u "/svg/defs/linearGradient[@id='linearGradient6204']/@id" -v 'linearGradient9999' text.txt 

I also tried again, adding the namespaces with -N but no luck. I found that if I delete the line:

xmlns="http://www.w3.org/2000/svg" 

from the file then the command I wrote above works.

What is the proper syntax for updating the SVG file above in the way I described?

Add Comment
1 Answer(s)

Explicit Namespace Declaration

Adding -N s=http://www.w3.org/2000/svg and then using the s: namespace prefix works:

xmlstarlet ed  -N s=http://www.w3.org/2000/svg -u "/s:svg/s:defs/s:linearGradient[@id='linearGradient6204']/@id" -v 'linearGradient9999' text.txt 

Implicit Declaration of Default Namespace

Starting with XMLStarlet v1.2.1, an explicit command line definition for the default namespace (such as is the case with OP’s SVG file) can be avoided via use of an automated binding of _ to the default namespace:

1.3. A More Convenient Solution

XML documents can also use different namespace prefixes, on any element in the document. In order to handle namespaces with greater ease, XMLStarlet (versions 1.2.1+) will use the namespace prefixes declared on the root element of the input document. The default namespace will be bound to the prefixes _ and DEFAULT (in versions 1.5.0+).

So, the above command line could be re-written as:

xmlstarlet ed -u "/_:svg/_:defs/_:linearGradient[@id='linearGradient6204']/@id" -v 'linearGradient9999' text.txt 
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.